Condividi tramite


Chiamata dell'API Web da un'applicazione Windows Phone 8 (C#)

di Robert McMurray

In questa esercitazione si apprenderà come creare uno scenario end-to-end completo costituito da un'applicazione API Web ASP.NET che fornisce un catalogo di libri a un'applicazione Windows Phone 8.

Panoramica

I servizi RESTful come API Web ASP.NET semplificano la creazione di applicazioni basate su HTTP per gli sviluppatori astraendo l'architettura per le applicazioni lato server e lato client. Invece di creare un protocollo proprietario basato su socket per la comunicazione, gli sviluppatori di API Web devono semplicemente pubblicare i metodi HTTP necessari per l'applicazione, ad esempio GET, POST, PUT, DELETE e gli sviluppatori di applicazioni client devono usare solo i metodi HTTP necessari per l'applicazione.

In questa esercitazione end-to-end si apprenderà come usare l'API Web per creare i progetti seguenti:

Prerequisiti

  • Visual Studio 2013 con Windows Phone 8 SDK installato
  • Windows 8 o versione successiva in un sistema a 64 bit con Hyper-V installato
  • Per un elenco dei requisiti aggiuntivi, vedere la sezione Requisiti di sistema nella pagina di download di Windows Phone SDK 8.0.

Nota

Se si intende testare la connettività tra l'API Web e Windows Phone 8 progetti nel sistema locale, è necessario seguire le istruzioni riportate nell'articolo Connessione dell'emulatore Windows Phone 8 alle applicazioni API Web in un computer locale per configurare l'ambiente di test.

Passaggio 1: Creazione del progetto bookstore dell'API Web

Il primo passaggio di questa esercitazione end-to-end consiste nel creare un progetto API Web che supporta tutte le operazioni CRUD; Si noti che si aggiungerà il progetto di applicazione Windows Phone a questa soluzione nel passaggio 2 di questa esercitazione.

  1. Aprire Visual Studio 2013.

  2. Fare clic su File, su Nuovoe quindi su Progetto.

  3. Quando viene visualizzata la finestra di dialogo Nuovo progetto , espandere Installato, quindi Modelli, Visual C#, quindi Web.

    Screenshot della finestra di dialogo
    Fare clic sull'immagine per espandere
  4. Evidenziare ASP.NET'applicazione Web, immettere BookStore come nome del progetto e quindi fare clic su OK.

  5. Quando viene visualizzata la finestra di dialogo Nuovo ASP.NET progetto , selezionare il modello API Web e quindi fare clic su OK.

    Screenshot della finestra di dialogo Libreria di progetti A S P dot NET, che mostra le opzioni del modello e le caselle di controllo per selezionare la cartella del modello e il riferimento principale.
    Fare clic sull'immagine per espandere
  6. Quando si apre il progetto API Web, rimuovere il controller di esempio dal progetto:

    1. Espandere la cartella Controllers in Esplora soluzioni.
    2. Fare clic con il pulsante destro del mouse sul file ValuesController.cs e quindi scegliere Elimina.
    3. Fare clic su OK quando viene richiesto di confermare l'eliminazione.
  7. Aggiungere un file di dati XML al progetto API Web; questo file contiene il contenuto del catalogo bookstore:

    1. Fare clic con il pulsante destro del mouse sulla cartella App_Data in Esplora soluzioni, quindi scegliere Aggiungi, quindi fare clic su Nuovo elemento.

    2. Quando viene visualizzata la finestra di dialogo Aggiungi nuovo elemento , evidenziare il modello di file XML .

    3. Assegnare al file il nome Books.xmle quindi fare clic su Aggiungi.

    4. Quando il file Books.xml viene aperto, sostituire il codice nel file con il codice XML del file di esempiobooks.xml su 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. Salvare e chiudere il file XML.

  8. Aggiungere il modello bookstore al progetto API Web; questo modello contiene la logica Create, Read, Update e Delete (CRUD) per l'applicazione bookstore:

    1. Fare clic con il pulsante destro del mouse sulla cartella Modelli in Esplora soluzioni, quindi scegliere Aggiungi e quindi fare clic su Classe.

    2. Quando viene visualizzata la finestra di dialogo Aggiungi nuovo elemento , denominare il file di classe BookDetails.cs e quindi fare clic su Aggiungi.

    3. Quando il file BookDetails.cs viene aperto, sostituire il codice nel file con quanto segue:

      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. Salvare e chiudere il file BookDetails.cs .

  9. Aggiungere il controller bookstore al progetto API Web:

    1. Fare clic con il pulsante destro del mouse sulla cartella Controller in Esplora soluzioni, quindi scegliere Aggiungi, quindi fare clic su Controller.

    2. Quando viene visualizzata la finestra di dialogo Aggiungi scaffolding , evidenziare Web API 2 Controller - Vuoto e quindi fare clic su Aggiungi.

    3. Quando viene visualizzata la finestra di dialogo Aggiungi controller , assegnare al controller il nome BooksController e quindi fare clic su Aggiungi.

    4. Quando il file BooksController.cs viene aperto, sostituire il codice nel file con il codice seguente:

      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. Salvare e chiudere il file BooksController.cs .

  10. Compilare l'applicazione API Web per verificare la presenza di errori.

Passaggio 2: Aggiunta del progetto catalogo bookstore Windows Phone 8

Il passaggio successivo di questo scenario end-to-end consiste nel creare l'applicazione del catalogo per Windows Phone 8. Questa applicazione userà il modello di app databound Windows Phone per l'interfaccia utente predefinita e userà l'applicazione API Web creata nel passaggio 1 di questa esercitazione come origine dati.

  1. Fare clic con il pulsante destro del mouse sulla soluzione BookStore in in Esplora soluzioni, quindi scegliere Aggiungi e quindi Nuovo progetto.

  2. Quando viene visualizzata la finestra di dialogo Nuovo progetto, espandere Installato, Visual C# e quindi Windows Phone.

  3. Evidenziare Windows Phone'app databound, immettere BookCatalog come nome e quindi fare clic su OK.

  4. Aggiungere il pacchetto NuGet Json.NET al progetto BookCatalog :

    1. Fare clic con il pulsante destro del mouse su Riferimenti per il progetto BookCatalog in Esplora soluzioni e quindi scegliere Gestisci pacchetti NuGet.
    2. Quando viene visualizzata la finestra di dialogo Gestisci pacchetti NuGet , espandere la sezione Online ed evidenziare nuget.org.
    3. Immettere Json.NET nel campo di ricerca e fare clic sull'icona di ricerca.
    4. Evidenziare Json.NET nei risultati della ricerca e quindi fare clic su Installa.
    5. Al termine dell'installazione, fare clic su Chiudi.
  5. Aggiungere il modello BookDetails al progetto BookCatalog ; contiene un modello generico della classe bookstore:

    1. Fare clic con il pulsante destro del mouse sul progetto BookCatalog in Esplora soluzioni, quindi scegliere Aggiungi, quindi fare clic su Nuova cartella.

    2. Assegnare alla nuova cartella il nome Models.

    3. Fare clic con il pulsante destro del mouse sulla cartella Modelli in Esplora soluzioni, quindi scegliere Aggiungi e quindi fare clic su Classe.

    4. Quando viene visualizzata la finestra di dialogo Aggiungi nuovo elemento , denominare il file di classe BookDetails.cs e quindi fare clic su Aggiungi.

    5. Quando il file BookDetails.cs viene aperto, sostituire il codice nel file con quanto segue:

      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. Salvare e chiudere il file BookDetails.cs .

  6. Aggiornare la classe MainViewModel.cs per includere la funzionalità per comunicare con l'applicazione API Web BookStore:

    1. Espandere la cartella ViewModels in Esplora soluzioni e quindi fare doppio clic sul file MainViewModel.cs .

    2. Quando il file MainViewModel.cs viene aperto, sostituire il codice nel file con il codice seguente; Si noti che sarà necessario aggiornare il valore della apiUrl costante con l'URL effettivo dell'API Web:

      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. Salvare e chiudere il file MainViewModel.cs .

  7. Aggiornare il file MainPage.xaml per personalizzare il nome dell'applicazione:

    1. Fare doppio clic sul file MainPage.xaml in Esplora soluzioni.

    2. Quando il file MainPage.xaml viene aperto, individuare le righe di codice seguenti:

      <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. Sostituire le righe con le seguenti:

      <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. Salvare e chiudere il file MainPage.xaml .

  8. Aggiornare il file DetailsPage.xaml per personalizzare gli elementi visualizzati:

    1. Fare doppio clic sul file DetailsPage.xaml in Esplora soluzioni.

    2. Quando il file DetailsPage.xaml viene aperto, individuare le righe di codice seguenti:

      <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. Sostituire le righe con le seguenti:

      <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. Salvare e chiudere il file DetailsPage.xaml .

  9. Compilare l'applicazione Windows Phone per verificare la presenza di errori.

Passaggio 3: Test della soluzione end-to-end

Come indicato nella sezione Prerequisiti di questa esercitazione, quando si testa la connettività tra l'API Web e Windows Phone 8 progetti nel sistema locale, è necessario seguire le istruzioni riportate nell'articolo Connessione dell'emulatore Windows Phone 8 alle applicazioni API Web in un computer locale per configurare l'ambiente di test.

Dopo aver configurato l'ambiente di test, sarà necessario impostare l'applicazione Windows Phone come progetto di avvio. A tale scopo, evidenziare l'applicazione BookCatalog in Esplora soluzioni e quindi fare clic su Imposta come progetto di avvio:

Screenshot della finestra esplora soluzioni, che mostra le opzioni di menu, per impostare l'applicazione windows phone nell'opzione
Fare clic sull'immagine per espandere

Quando si preme F5, Visual Studio avvierà sia l'emulatore Windows Phone, che visualizzerà un messaggio "Attendere" mentre i dati dell'applicazione vengono recuperati dall'API Web:

Screenshot della finestra esplora soluzioni, che mostra l'emulatore di telefono visualizzato sopra di esso, visualizzando il titolo Book Store e il messaggio 'please wait'.
Fare clic sull'immagine per espandere

Se tutto ha esito positivo, verrà visualizzato il catalogo:

Screenshot della finestra esplora soluzioni, che mostra l'emulatore di telefono sopra di esso, visualizzando il Book Store con i titoli nel catalogo.
Fare clic sull'immagine per espandere

Se si tocca un titolo di libro, l'applicazione visualizzerà la descrizione del libro:

Screenshot dell'emulatore di telefono, nella finestra esplora soluzioni, che mostra il titolo e la descrizione di un libro.
Fare clic sull'immagine per espandere

Se l'applicazione non riesce a comunicare con l'API Web, verrà visualizzato un messaggio di errore:

Screenshot dell'emulatore di telefono, visualizzato nella finestra esplora soluzioni, che mostra un messaggio di errore
Fare clic sull'immagine per espandere

Se si tocca il messaggio di errore, verranno visualizzati altri dettagli sull'errore:

Screenshot dell'emulatore di telefono, nella finestra di dialogo Esplora soluzioni, che mostra
Fare clic sull'immagine per espandere