Sdílet prostřednictvím


Volání webového rozhraní API z aplikace pro Windows Phone 8 (C#)

Robert McMurray

V tomto kurzu se dozvíte, jak vytvořit kompletní scénář skládající se z aplikace webového rozhraní API pro ASP.NET, která poskytuje katalog knih pro aplikaci Windows Phone 8.

Přehled

Služby RESTful, jako je ASP.NET Webové rozhraní API, zjednodušují vývojářům vytváření aplikací založených na protokolu HTTP tím, že abstraktují architekturu pro aplikace na straně serveru i klienta. Místo vytváření proprietárního protokolu založeného na soketu pro komunikaci potřebují vývojáři webového rozhraní API jednoduše publikovat požadované metody HTTP pro svou aplikaci (například GET, POST, PUT, DELETE) a vývojáři klientských aplikací potřebují pouze používat metody HTTP, které jsou nezbytné pro jejich aplikaci.

V tomto komplexním kurzu se naučíte, jak pomocí webového rozhraní API vytvořit následující projekty:

Požadavky

  • Visual Studio 2013 s nainstalovanou sadou WINDOWS PHONE 8 SDK
  • Windows 8 nebo novější v 64bitovém systému s nainstalovanou technologií Hyper-V
  • Seznam dalších požadavků najdete v části Požadavky na systém na stránce pro stažení sady Windows Phone SDK 8.0.

Poznámka

Pokud budete testovat připojení mezi webovými rozhraními API a projekty Windows Phone 8 v místním systému, budete muset nastavit testovací prostředí podle pokynů v článku Připojení emulátoru Windows Phone 8 k aplikacím webového rozhraní API v místním počítači.

Krok 1: Vytvoření projektu knihkupectví webového rozhraní API

Prvním krokem tohoto kompletního kurzu je vytvoření projektu webového rozhraní API, který podporuje všechny operace CRUD. Všimněte si, že projekt Windows Phone aplikace přidáte do tohoto řešení ve 2. kroku tohoto kurzu.

  1. Otevřete Visual Studio 2013.

  2. Klikněte na File (Soubor), New (Nový) a project (Projekt).

  3. Po zobrazení dialogového okna Nový projekt rozbalte nainstalované, šablony, visual C# a web.

    Snímek obrazovky s dialogovým oknem Nový projekt, ve kterém je v nabídce cesta k souboru a zvýrazněný postup vytvoření nového projektu
    Kliknutím na obrázek rozbalíte
  4. Zvýrazněte ASP.NET webovou aplikaci, jako název projektu zadejte BookStore a klikněte na OK.

  5. Po zobrazení dialogového okna Nový projekt ASP.NET vyberte šablonu Webové rozhraní API a klikněte na OK.

    Snímek obrazovky s dialogovým oknem knihkupectví projektů A S P dot NET zobrazující možnosti šablony a zaškrtávací políčka pro výběr složky šablon a základního odkazu
    Kliknutím na obrázek rozbalíte
  6. Po otevření projektu webového rozhraní API odeberte z projektu ukázkový kontroler:

    1. V Průzkumníku řešení rozbalte složku Kontrolery .
    2. Klikněte pravým tlačítkem na soubor ValuesController.cs a potom klikněte na Odstranit.
    3. Po zobrazení výzvy k potvrzení odstranění klikněte na OK .
  7. Přidat datový soubor XML do projektu webového rozhraní API; tento soubor obsahuje obsah katalogu knihkupectví:

    1. V Průzkumníku řešení klikněte pravým tlačítkem na složku App_Data , klikněte na Přidat a potom klikněte na Nová položka.

    2. Po zobrazení dialogového okna Přidat novou položku zvýrazněte šablonu Soubor XML .

    3. Pojmenujte soubor Books.xmla potom klikněte na Přidat.

    4. Po otevření souboruBooks.xml nahraďte kód v souboru kódem XML z ukázkového books.xml souboru na webu MSDN:

      <?xml version="1.0" encoding="utf-8"?>
      <catalog>
        <book id="bk101">
          <author>Gambardella, Matthew</author>
          <title>XML Developer's Guide</title>
          <genre>Computer</genre>
          <price>44.95</price>
          <publish_date>2000-10-01</publish_date>
          <description>
            An in-depth look at creating applications
            with XML.
          </description>
        </book>
        <book id="bk102">
          <author>Ralls, Kim</author>
          <title>Midnight Rain</title>
          <genre>Fantasy</genre>
          <price>5.95</price>
          <publish_date>2000-12-16</publish_date>
          <description>
            A former architect battles corporate zombies,
            an evil sorceress, and her own childhood to become queen
            of the world.
          </description>
        </book>
        <book id="bk103">
          <author>Corets, Eva</author>
          <title>Maeve Ascendant</title>
          <genre>Fantasy</genre>
          <price>5.95</price>
          <publish_date>2000-11-17</publish_date>
          <description>
            After the collapse of a nanotechnology
            society in England, the young survivors lay the
            foundation for a new society.
          </description>
        </book>
        <book id="bk104">
          <author>Corets, Eva</author>
          <title>Oberon's Legacy</title>
          <genre>Fantasy</genre>
          <price>5.95</price>
          <publish_date>2001-03-10</publish_date>
          <description>
            In post-apocalypse England, the mysterious
            agent known only as Oberon helps to create a new life
            for the inhabitants of London. Sequel to Maeve
            Ascendant.
          </description>
        </book>
        <book id="bk105">
          <author>Corets, Eva</author>
          <title>The Sundered Grail</title>
          <genre>Fantasy</genre>
          <price>5.95</price>
          <publish_date>2001-09-10</publish_date>
          <description>
            The two daughters of Maeve, half-sisters,
            battle one another for control of England. Sequel to
            Oberon's Legacy.
          </description>
        </book>
        <book id="bk106">
          <author>Randall, Cynthia</author>
          <title>Lover Birds</title>
          <genre>Romance</genre>
          <price>4.95</price>
          <publish_date>2000-09-02</publish_date>
          <description>
            When Carla meets Paul at an ornithology
            conference, tempers fly as feathers get ruffled.
          </description>
        </book>
        <book id="bk107">
          <author>Thurman, Paula</author>
          <title>Splish Splash</title>
          <genre>Romance</genre>
          <price>4.95</price>
          <publish_date>2000-11-02</publish_date>
          <description>
            A deep sea diver finds true love twenty
            thousand leagues beneath the sea.
          </description>
        </book>
        <book id="bk108">
          <author>Knorr, Stefan</author>
          <title>Creepy Crawlies</title>
          <genre>Horror</genre>
          <price>4.95</price>
          <publish_date>2000-12-06</publish_date>
          <description>
            An anthology of horror stories about roaches,
            centipedes, scorpions  and other insects.
          </description>
        </book>
        <book id="bk109">
          <author>Kress, Peter</author>
          <title>Paradox Lost</title>
          <genre>Science Fiction</genre>
          <price>6.95</price>
          <publish_date>2000-11-02</publish_date>
          <description>
            After an inadvertant trip through a Heisenberg
            Uncertainty Device, James Salway discovers the problems
            of being quantum.
          </description>
        </book>
        <book id="bk110">
          <author>O'Brien, Tim</author>
          <title>Microsoft .NET: The Programming Bible</title>
          <genre>Computer</genre>
          <price>36.95</price>
          <publish_date>2000-12-09</publish_date>
          <description>
            Microsoft's .NET initiative is explored in
            detail in this deep programmer's reference.
          </description>
        </book>
        <book id="bk111">
          <author>O'Brien, Tim</author>
          <title>MSXML3: A Comprehensive Guide</title>
          <genre>Computer</genre>
          <price>36.95</price>
          <publish_date>2000-12-01</publish_date>
          <description>
            The Microsoft MSXML3 parser is covered in
            detail, with attention to XML DOM interfaces, XSLT processing,
            SAX and more.
          </description>
        </book>
        <book id="bk112">
          <author>Galos, Mike</author>
          <title>Visual Studio 7: A Comprehensive Guide</title>
          <genre>Computer</genre>
          <price>49.95</price>
          <publish_date>2001-04-16</publish_date>
          <description>
            Microsoft Visual Studio 7 is explored in depth,
            looking at how Visual Basic, Visual C++, C#, and ASP+ are
            integrated into a comprehensive development
            environment.
          </description>
        </book>
      </catalog>
      
    5. Uložte a zavřete soubor XML.

  8. Přidejte model knihkupectví do projektu webového rozhraní API. Tento model obsahuje logiku CRUD (Create, Read, Update a Delete) pro aplikaci knihkupectví:

    1. V Průzkumníku řešení klikněte pravým tlačítkem na složku Models , klikněte na Přidat a potom klikněte na Třída.

    2. Když se zobrazí dialogové okno Přidat novou položku , pojmenujte soubor třídy BookDetails.cs a pak klikněte na Přidat.

    3. Při otevření souboru BookDetails.cs nahraďte kód v souboru následujícím kódem:

      using System;
      using System.Collections.Generic;
      using System.ComponentModel.DataAnnotations;
      using System.Linq;
      using System.Xml;
      using System.Xml.Linq;
      using System.Xml.XPath;
      using System.Web;
      
      namespace BookStore.Models
      {
          /// <summary>
          /// Define a class that will hold the detailed information for a book.
          /// </summary>
          public class BookDetails
          {
              [Required]
              public String Id { get; set; }
              [Required]
              public String Title { get; set; }
              public String Author { get; set; }
              public String Genre { get; set; }
              public Decimal Price { get; set; }
              public DateTime PublishDate { get; set; }
              public String Description { get; set; }
          }
      
          /// <summary>
          /// Define an interface which contains the methods for the book repository.
          /// </summary>
          public interface IBookRepository
          {
              BookDetails CreateBook(BookDetails book);
              IEnumerable<BookDetails> ReadAllBooks();
              BookDetails ReadBook(String id);
              BookDetails UpdateBook(String id, BookDetails book);
              Boolean DeleteBook(String id);
          }
      
          /// <summary>
          /// Define a class based on the book repository interface which contains the method implementations.
          /// </summary>
          public class BookRepository : IBookRepository
          {
              private string xmlFilename = null;
              private XDocument xmlDocument = null;
      
              /// <summary>
              /// Define the class constructor.
              /// </summary>
              public BookRepository()
              {
                  try
                  {
                      // Determine the path to the books.xml file.
                      xmlFilename = HttpContext.Current.Server.MapPath("~/app_data/books.xml");
                      // Load the contents of the books.xml file into an XDocument object.
                      xmlDocument = XDocument.Load(xmlFilename);
                  }
                  catch (Exception ex)
                  {
                      // Rethrow the exception.
                      throw ex;
                  }
              }
      
              /// <summary>
              /// Method to add a new book to the catalog.
              /// Defines the implementation of the POST method.
              /// </summary>
              public BookDetails CreateBook(BookDetails book)
              {
                  try
                  {
                      // Retrieve the book with the highest ID from the catalog.
                      var highestBook = (
                          from bookNode in xmlDocument.Elements("catalog").Elements("book")
                          orderby bookNode.Attribute("id").Value descending
                          select bookNode).Take(1);
                      // Extract the ID from the book data.
                      string highestId = highestBook.Attributes("id").First().Value;
                      // Create an ID for the new book.
                      string newId = "bk" + (Convert.ToInt32(highestId.Substring(2)) + 1).ToString();
                      // Verify that this book ID does not currently exist.
                      if (this.ReadBook(newId) == null)
                      {
                          // Retrieve the parent element for the book catalog.
                          XElement bookCatalogRoot = xmlDocument.Elements("catalog").Single();
                          // Create a new book element.
                          XElement newBook = new XElement("book", new XAttribute("id", newId));
                          // Create elements for each of the book's data items.
                          XElement[] bookInfo = FormatBookData(book);
                          // Add the element to the book element.
                          newBook.ReplaceNodes(bookInfo);
                          // Append the new book to the XML document.
                          bookCatalogRoot.Add(newBook);
                          // Save the XML document.
                          xmlDocument.Save(xmlFilename);
                          // Return an object for the newly-added book.
                          return this.ReadBook(newId);
                      }
                  }
                  catch (Exception ex)
                  {
                      // Rethrow the exception.
                      throw ex;
                  }
                  // Return null to signify failure.
                  return null;
              }
      
              /// <summary>
              /// Method to retrieve all of the books in the catalog.
              /// Defines the implementation of the non-specific GET method.
              /// </summary>
              public IEnumerable<BookDetails> ReadAllBooks()
              {
                  try
                  {
                      // Return a list that contains the catalog of book ids/titles.
                      return (
                          // Query the catalog of books.
                          from book in xmlDocument.Elements("catalog").Elements("book")
                          // Sort the catalog based on book IDs.
                          orderby book.Attribute("id").Value ascending
                          // Create a new instance of the detailed book information class.
                          select new BookDetails
                          {
                              // Populate the class with data from each of the book's elements.
                              Id = book.Attribute("id").Value,
                              Author = book.Element("author").Value,
                              Title = book.Element("title").Value,
                              Genre = book.Element("genre").Value,
                              Price = Convert.ToDecimal(book.Element("price").Value),
                              PublishDate = Convert.ToDateTime(book.Element("publish_date").Value),
                              Description = book.Element("description").Value
                          }).ToList();
                  }
                  catch (Exception ex)
                  {
                      // Rethrow the exception.
                      throw ex;
                  }
              }
      
              /// <summary>
              /// Method to retrieve a specific book from the catalog.
              /// Defines the implementation of the ID-specific GET method.
              /// </summary>
              public BookDetails ReadBook(String id)
              {
                  try
                  {
                      // Retrieve a specific book from the catalog.
                      return (
                          // Query the catalog of books.
                          from book in xmlDocument.Elements("catalog").Elements("book")
                          // Specify the specific book ID to query.
                          where book.Attribute("id").Value.Equals(id)
                          // Create a new instance of the detailed book information class.
                          select new BookDetails
                          {
                              // Populate the class with data from each of the book's elements.
                              Id = book.Attribute("id").Value,
                              Author = book.Element("author").Value,
                              Title = book.Element("title").Value,
                              Genre = book.Element("genre").Value,
                              Price = Convert.ToDecimal(book.Element("price").Value),
                              PublishDate = Convert.ToDateTime(book.Element("publish_date").Value),
                              Description = book.Element("description").Value
                          }).Single();
                  }
                  catch
                  {
                      // Return null to signify failure.
                      return null;
                  }
              }
      
              /// <summary>
              /// Populates a book BookDetails class with the data for a book.
              /// </summary>
              private XElement[] FormatBookData(BookDetails book)
              {
                  XElement[] bookInfo =
                  {
                      new XElement("author", book.Author),
                      new XElement("title", book.Title),
                      new XElement("genre", book.Genre),
                      new XElement("price", book.Price.ToString()),
                      new XElement("publish_date", book.PublishDate.ToString()),
                      new XElement("description", book.Description)
                  };
                  return bookInfo;
              }
      
              /// <summary>
              /// Method to update an existing book in the catalog.
              /// Defines the implementation of the PUT method.
              /// </summary>
              public BookDetails UpdateBook(String id, BookDetails book)
              {
                  try
                  {
                      // Retrieve a specific book from the catalog.
                      XElement updateBook = xmlDocument.XPathSelectElement(String.Format("catalog/book[@id='{0}']", id));
                      // Verify that the book exists.
                      if (updateBook != null)
                      {
                          // Create elements for each of the book's data items.
                          XElement[] bookInfo = FormatBookData(book);
                          // Add the element to the book element.
                          updateBook.ReplaceNodes(bookInfo);
                          // Save the XML document.
                          xmlDocument.Save(xmlFilename);
                          // Return an object for the updated book.
                          return this.ReadBook(id);
                      }
                  }
                  catch (Exception ex)
                  {
                      // Rethrow the exception.
                      throw ex;
                  }
                  // Return null to signify failure.
                  return null;
              }
      
              /// <summary>
              /// Method to remove an existing book from the catalog.
              /// Defines the implementation of the DELETE method.
              /// </summary>
              public Boolean DeleteBook(String id)
              {
                  try
                  {
                      if (this.ReadBook(id) != null)
                      {
                          // Remove the specific child node from the catalog.
                          xmlDocument
                              .Elements("catalog")
                              .Elements("book")
                              .Where(x => x.Attribute("id").Value.Equals(id))
                              .Remove();
                          // Save the XML document.
                          xmlDocument.Save(xmlFilename);
                          // Return a success status.
                          return true;
                      }
                      else
                      {
                          // Return a failure status.
                          return false;
                      }
                  }
                  catch (Exception ex)
                  {
                      // Rethrow the exception.
                      throw ex;
                  }
              }
          }
      }
      
    4. Uložte a zavřete soubor BookDetails.cs .

  9. Přidejte kontroler knihkupectví do projektu webového rozhraní API:

    1. V Průzkumníku řešení klikněte pravým tlačítkem na složku Kontrolery , klikněte na Přidat a potom klikněte na Kontroler.

    2. Po zobrazení dialogového okna Přidat uživatelské rozhraní zvýrazněte kontroler webového rozhraní API 2 – prázdný a pak klikněte na Přidat.

    3. Po zobrazení dialogového okna Přidat kontroler pojmenujte kontroler BooksController a klikněte na Přidat.

    4. Při otevření souboru BooksController.cs nahraďte kód v souboru následujícím kódem:

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Net;
      using System.Net.Http;
      using System.Web.Http;
      using BookStore.Models;
      
      namespace BookStore.Controllers
      {
          public class BooksController : ApiController
          {
              private BookRepository repository = null;
      
              // Define the class constructor.
              public BooksController()
              {
                  this.repository = new BookRepository();
              }
      
              /// <summary>
              /// Method to retrieve all of the books in the catalog.
              /// Example: GET api/books
              /// </summary>
              [HttpGet]
              public HttpResponseMessage Get()
              {
                  IEnumerable<BookDetails> books = this.repository.ReadAllBooks();
                  if (books != null)
                  {
                      return Request.CreateResponse<IEnumerable<BookDetails>>(HttpStatusCode.OK, books);
                  }
                  else
                  {
                      return Request.CreateResponse(HttpStatusCode.NotFound);
                  }
              }
      
              /// <summary>
              /// Method to retrieve a specific book from the catalog.
              /// Example: GET api/books/5
              /// </summary>
              [HttpGet]
              public HttpResponseMessage Get(String id)
              {
                  BookDetails book = this.repository.ReadBook(id);
                  if (book != null)
                  {
                      return Request.CreateResponse<BookDetails>(HttpStatusCode.OK, book);
                  }
                  else
                  {
                      return Request.CreateResponse(HttpStatusCode.NotFound);
                  }
              }
      
              /// <summary>
              /// Method to add a new book to the catalog.
              /// Example: POST api/books
              /// </summary>
              [HttpPost]
              public HttpResponseMessage Post(BookDetails book)
              {
                  if ((this.ModelState.IsValid) && (book != null))
                  {
                      BookDetails newBook = this.repository.CreateBook(book);
                      if (newBook != null)
                      {
                          var httpResponse = Request.CreateResponse<BookDetails>(HttpStatusCode.Created, newBook);
                          string uri = Url.Link("DefaultApi", new { id = newBook.Id });
                          httpResponse.Headers.Location = new Uri(uri);
                          return httpResponse;
                      }
                  }
                  return Request.CreateResponse(HttpStatusCode.BadRequest);
              }
      
              /// <summary>
              /// Method to update an existing book in the catalog.
              /// Example: PUT api/books/5
              /// </summary>
              [HttpPut]
              public HttpResponseMessage Put(String id, BookDetails book)
              {
                  if ((this.ModelState.IsValid) && (book != null) && (book.Id.Equals(id)))
                  {
                      BookDetails modifiedBook = this.repository.UpdateBook(id, book);
                      if (modifiedBook != null)
                      {
                          return Request.CreateResponse<BookDetails>(HttpStatusCode.OK, modifiedBook);
                      }
                      else
                      {
                          return Request.CreateResponse(HttpStatusCode.NotFound);
                      }
                  }
                  return Request.CreateResponse(HttpStatusCode.BadRequest);
              }
      
              /// <summary>
              /// Method to remove an existing book from the catalog.
              /// Example: DELETE api/books/5
              /// </summary>
              [HttpDelete]
              public HttpResponseMessage Delete(String id)
              {
                  BookDetails book = this.repository.ReadBook(id);
                  if (book != null)
                  {
                      if (this.repository.DeleteBook(id))
                      {
                          return Request.CreateResponse(HttpStatusCode.OK);
                      }
                  }
                  else
                  {
                      return Request.CreateResponse(HttpStatusCode.NotFound);
                  }
                  return Request.CreateResponse(HttpStatusCode.BadRequest);
              }
          }
      }
      
    5. Uložte a zavřete soubor BooksController.cs .

  10. Sestavte aplikaci webového rozhraní API pro kontrolu chyb.

Krok 2: Přidání projektu katalogu knihkupectví Windows Phone 8

Dalším krokem tohoto kompletního scénáře je vytvoření aplikace katalogu pro Windows Phone 8. Tato aplikace použije šablonu Windows Phone Databound App pro výchozí uživatelské rozhraní a jako zdroj dat použije aplikaci webového rozhraní API, kterou jste vytvořili v kroku 1 tohoto kurzu.

  1. V průzkumníku řešení klikněte pravým tlačítkem na řešení BookStore , klikněte na Přidat a pak na Nový projekt.

  2. Po zobrazení dialogového okna Nový projekt rozbalte Nainstalované, visual C# a Windows Phone.

  3. Zvýrazněte Windows Phone Databound App, jako název zadejte BookCatalog a klikněte na OK.

  4. Přidejte balíček NuGet Json.NET do projektu BookCatalog :

    1. V průzkumníku řešení klikněte pravým tlačítkem na Reference pro projekt BookCatalog a pak klikněte na Spravovat balíčky NuGet.
    2. Když se zobrazí dialogové okno Spravovat balíčky NuGet , rozbalte oddíl Online a zvýrazněte nuget.org.
    3. Do vyhledávacího pole zadejte Json.NET a klikněte na ikonu hledání.
    4. Ve výsledcích hledání zvýrazněte Json.NET a pak klikněte na Nainstalovat.
    5. Po dokončení instalace klikněte na Zavřít.
  5. Přidat BookDetails model bookCatalog projektu; obsahuje obecný model třídy knihkupectví:

    1. V průzkumníku řešení klikněte pravým tlačítkem na projekt BookCatalog , klikněte na Přidat a potom klikněte na Nová složka.

    2. Pojmenujte novou složku Models.

    3. V Průzkumníku řešení klikněte pravým tlačítkem na složku Models , klikněte na Přidat a potom klikněte na Třída.

    4. Když se zobrazí dialogové okno Přidat novou položku , pojmenujte soubor třídy BookDetails.cs a pak klikněte na Přidat.

    5. Při otevření souboru BookDetails.cs nahraďte kód v souboru následujícím kódem:

      using System;
      using System.Text;
      
      namespace BookCatalog.Models
      {
          /// <summary>
          /// Define a class that will hold the detailed information for a book.
          /// </summary>
          public class BookDetails
          {
              public String Id { get; set; }
              public String Title { get; set; }
              public String Author { get; set; }
              public String Genre { get; set; }
              public Decimal Price { get; set; }
              public DateTime PublishDate { get; set; }
              public String Description { get; set; }
          }
      }
      
    6. Uložte a zavřete soubor BookDetails.cs .

  6. Aktualizujte třídu MainViewModel.cs tak, aby zahrnovala funkci pro komunikaci s aplikací rozhraní API BookStore Web:

    1. V Průzkumníku řešení rozbalte složku ViewModels a poklikejte na soubor MainViewModel.cs .

    2. Při otevření souboru MainViewModel.cs nahraďte kód v souboru následujícím kódem: Všimněte si, že hodnotu konstanty apiUrl budete muset aktualizovat na skutečnou adresu URL vašeho webového rozhraní API:

      using System;
      using System.Collections.ObjectModel;
      using System.ComponentModel;
      using System.Net;
      using System.Net.NetworkInformation;
      using BookCatalog.Resources;
      using System.Collections.Generic;
      using Newtonsoft.Json;
      using BookCatalog.Models;
      
      namespace BookCatalog.ViewModels
      {
          public class MainViewModel : INotifyPropertyChanged
          {
              const string apiUrl = @"http://www.contoso.com/api/Books";
      
              public MainViewModel()
              {
                  this.Items = new ObservableCollection<ItemViewModel>();
              }
      
              /// <summary>
              /// A collection for ItemViewModel objects.
              /// </summary>
              public ObservableCollection<ItemViewModel> Items { get; private set; }
      
              public bool IsDataLoaded
              {
                  get;
                  private set;
              }
      
              /// <summary>
              /// Creates and adds a few ItemViewModel objects into the Items collection.
              /// </summary>
              public void LoadData()
              {
                  if (this.IsDataLoaded == false)
                  {
                      this.Items.Clear();
                      this.Items.Add(new ItemViewModel() { ID = "0", LineOne = "Please Wait...", LineTwo = "Please wait while the catalog is downloaded from the server.", LineThree = null });
                      WebClient webClient = new WebClient();
                      webClient.Headers["Accept"] = "application/json";
                      webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadCatalogCompleted);
                      webClient.DownloadStringAsync(new Uri(apiUrl));
                  }
              }
      
              private void webClient_DownloadCatalogCompleted(object sender, DownloadStringCompletedEventArgs e)
              {
                  try
                  {
                      this.Items.Clear();
                      if (e.Result != null)
                      {
                          var books = JsonConvert.DeserializeObject<BookDetails[]>(e.Result);
                          int id = 0;
                          foreach (BookDetails book in books)
                          {
                              this.Items.Add(new ItemViewModel()
                              {
                                  ID = (id++).ToString(),
                                  LineOne = book.Title,
                                  LineTwo = book.Author,
                                  LineThree = book.Description.Replace("\n", " ")
                              });
                          }
                          this.IsDataLoaded = true;
                      }
                  }
                  catch (Exception ex)
                  {
                      this.Items.Add(new ItemViewModel()
                      {
                          ID = "0",
                          LineOne = "An Error Occurred",
                          LineTwo = String.Format("The following exception occured: {0}", ex.Message),
                          LineThree = String.Format("Additional inner exception information: {0}", ex.InnerException.Message)
                      });
                  }
              }
      
              public event PropertyChangedEventHandler PropertyChanged;
              private void NotifyPropertyChanged(String propertyName)
              {
                  PropertyChangedEventHandler handler = PropertyChanged;
                  if (null != handler)
                  {
                      handler(this, new PropertyChangedEventArgs(propertyName));
                  }
              }
          }
      }
      
    3. Uložte a zavřete soubor MainViewModel.cs .

  7. Aktualizujte soubor MainPage.xaml a upravte název aplikace:

    1. V průzkumníku řešení poklikejte na soubor MainPage.xaml .

    2. Při otevření souboru MainPage.xaml vyhledejte následující řádky kódu:

      <StackPanel Grid.Row="0" Margin="12,17,0,28">
          <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/> 
          <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
      </StackPanel>
      
    3. Nahraďte tyto řádky následujícím kódem:

      <StackPanel Grid.Row="0" Margin="12,17,0,28">
          <TextBlock Text="Book Store" Style="{StaticResource PhoneTextTitle1Style}"/> 
          <TextBlock Text="Current Catalog" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle2Style}"/>
      </StackPanel>
      
    4. Uložte a zavřete soubor MainPage.xaml .

  8. Aktualizujte soubor DetailsPage.xaml tak, aby se zobrazované položky přizpůsobily:

    1. V průzkumníku řešení poklikejte na soubor DetailsPage.xaml .

    2. Při otevření souboru DetailsPage.xaml vyhledejte následující řádky kódu:

      <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
          <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
          <TextBlock Text="{Binding LineOne}" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
      </StackPanel>
      
    3. Nahraďte tyto řádky následujícím kódem:

      <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
          <TextBlock Text="Book Store" Style="{StaticResource PhoneTextTitle1Style}"/>
          <TextBlock Text="{Binding LineOne}" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle2Style}"/>
      </StackPanel>
      
    4. Uložte a zavřete soubor DetailsPage.xaml .

  9. Sestavte aplikaci Windows Phone a zkontrolujte chyby.

Krok 3: Testování kompletního řešení

Jak je uvedeno v části Požadavky tohoto kurzu, při testování připojení mezi webovými rozhraními API a projekty Windows Phone 8 v místním systému budete muset postupovat podle pokynů v článku Připojení emulátoru Windows Phone 8 k aplikacím webového rozhraní API v místním počítači a nastavit testovací prostředí.

Jakmile budete mít testovací prostředí nakonfigurované, budete muset nastavit Windows Phone aplikaci jako spouštěný projekt. Uděláte to tak, že v průzkumníku řešení zvýrazníte aplikaci BookCatalog a pak kliknete na Nastavit jako po spuštění projektu:

Snímek obrazovky s oknem průzkumníka řešení s možnostmi nabídky pro nastavení aplikace windows phone v možnosti nastavit jako spouštěcí projekt
Kliknutím na obrázek rozbalíte

Když stisknete klávesu F5, Visual Studio spustí emulátor Windows Phone, který zobrazí zprávu "Počkejte prosím", zatímco se data aplikace načtou z webového rozhraní API:

Snímek obrazovky s oknem Průzkumníka řešení, na kterém se zobrazuje automaticky otevírané okno emulátoru telefonu s názvem Obchod s knihami a zprávou
Kliknutím na obrázek rozbalíte

Pokud je vše úspěšné, měl by se zobrazit katalog:

Snímek obrazovky s oknem průzkumníka řešení, nad kterým je emulátor telefonu a knihou obchod s názvy v katalogu
Kliknutím na obrázek rozbalíte

Pokud klepnete na název knihy, aplikace zobrazí popis knihy:

Snímek obrazovky emulátoru telefonu nad oknem průzkumníka řešení zobrazující název a popis knihy
Kliknutím na obrázek rozbalíte

Pokud aplikace nemůže komunikovat s webovým rozhraním API, zobrazí se chybová zpráva:

Snímek obrazovky emulátoru telefonu, který se zobrazuje v okně průzkumníka řešení a zobrazuje zprávu
Kliknutím na obrázek rozbalíte

Pokud klepnete na chybovou zprávu, zobrazí se všechny další podrobnosti o chybě:

Snímek obrazovky emulátoru telefonu nad dialogovým oknem Průzkumníka řešení se zprávou Došlo k chybě a podrobnostem o chybě
Kliknutím na obrázek rozbalíte