Aufrufen des Web-API über eine Windows Phone 8-Anwendung (C#)

von Robert McMurray

In diesem Tutorial erfahren Sie, wie Sie ein vollständiges End-to-End-Szenario erstellen, das aus einer ASP.NET-Web-API Anwendung besteht, die einen Katalog von Büchern für eine Windows Phone 8-Anwendung bereitstellt.

Überblick

RESTful-Dienste wie ASP.NET-Web-API vereinfachen die Erstellung von HTTP-basierten Anwendungen für Entwickler, indem sie die Architektur für serverseitige und clientseitige Anwendungen abstrahieren. Statt ein proprietäres socketbasiertes Protokoll für die Kommunikation zu erstellen, müssen Web-API-Entwickler einfach die erforderlichen HTTP-Methoden für ihre Anwendung veröffentlichen (z. B. GET, POST, PUT, DELETE), und Clientanwendungsentwickler müssen nur die HTTP-Methoden nutzen, die für ihre Anwendung erforderlich sind.

In diesem End-to-End-Tutorial erfahren Sie, wie Sie die Web-API verwenden, um die folgenden Projekte zu erstellen:

Voraussetzungen

  • Visual Studio 2013 mit installiertem Windows Phone 8 SDK
  • Windows 8 oder höher auf einem 64-Bit-System mit installiertem Hyper-V
  • Eine Liste der zusätzlichen Anforderungen finden Sie im Abschnitt Systemanforderungen auf der Downloadseite für Windows Phone SDK 8.0.

Hinweis

Wenn Sie die Konnektivität zwischen Web-API und Windows Phone 8-Projekten auf Ihrem lokalen System testen möchten, müssen Sie die Anweisungen im Artikel Verbinden des Windows Phone 8 Emulators mit Web-API-Anwendungen auf einem lokalen Computer befolgen, um Ihre Testumgebung einzurichten.

Schritt 1: Erstellen des Web-API-Buchspeicherprojekts

Der erste Schritt dieses End-to-End-Tutorials besteht darin, ein Web-API-Projekt zu erstellen, das alle CRUD-Vorgänge unterstützt. Beachten Sie, dass Sie der Projektmappe in Schritt 2 dieses Tutorials das Windows Phone-Anwendungsprojekt hinzufügen.

  1. Öffnen Sie Visual Studio 2013.

  2. Klicken Sie auf Datei, dann auf Neu und dann auf Projekt.

  3. Wenn das Dialogfeld Neues Projekt angezeigt wird, erweitern Sie Installiert, dann Vorlagen, dann Visual C# und dann Web.

    Screenshot des Dialogfelds
    Klicken Sie auf das Bild, um sie zu erweitern.
  4. Markieren Sie ASP.NET Webanwendung, geben Sie BookStore als Projektnamen ein, und klicken Sie dann auf OK.

  5. Wenn das Dialogfeld Neues ASP.NET Projekt angezeigt wird, wählen Sie die Web-API-Vorlage aus, und klicken Sie dann auf OK.

    Screenshot des Dialogfelds
    Klicken Sie auf das Bild, um sie zu erweitern.
  6. Wenn das Web-API-Projekt geöffnet wird, entfernen Sie den Beispielcontroller aus dem Projekt:

    1. Erweitern Sie den Ordner Controller im Projektmappen-Explorer.
    2. Klicken Sie mit der rechten Maustaste auf die Datei ValuesController.cs , und klicken Sie dann auf Löschen.
    3. Klicken Sie auf OK , wenn Sie aufgefordert werden, den Löschvorgang zu bestätigen.
  7. Fügen Sie dem Web-API-Projekt eine XML-Datendatei hinzu. Diese Datei enthält den Inhalt des Buchhandlungskatalogs:

    1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner App_Data , klicken Sie dann auf Hinzufügen, und klicken Sie dann auf Neues Element.

    2. Wenn das Dialogfeld Neues Element hinzufügen angezeigt wird, markieren Sie die XML-Dateivorlage .

    3. Benennen Sie die Datei Books.xml, und klicken Sie dann auf Hinzufügen.

    4. Wenn die Books.xml-Datei geöffnet wird, ersetzen Sie den Code in der Datei durch den XML-Code aus der Beispieldateibooks.xml auf 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. Speichern und schließen Sie die XML-Datei.

  8. Fügen Sie das Buchhandlungsmodell dem Web-API-Projekt hinzu. Dieses Modell enthält die CRUD-Logik (Create, Read, Update, Delete) für die Buchhandlungsanwendung:

    1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Modelle , klicken Sie dann auf Hinzufügen, und klicken Sie dann auf Klasse.

    2. Wenn das Dialogfeld Neues Element hinzufügen angezeigt wird, geben Sie der Klassendatei den Namen BookDetails.cs, und klicken Sie dann auf Hinzufügen.

    3. Wenn die Datei BookDetails.cs geöffnet wird, ersetzen Sie den Code in der Datei durch Folgendes:

      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. Speichern und schließen Sie die Datei BookDetails.cs .

  9. Fügen Sie den Buchspeichercontroller dem Web-API-Projekt hinzu:

    1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Controller , klicken Sie dann auf Hinzufügen, und klicken Sie dann auf Controller.

    2. Wenn das Dialogfeld Gerüst hinzufügen angezeigt wird, markieren Sie Web-API 2-Controller – Leer, und klicken Sie dann auf Hinzufügen.

    3. Wenn das Dialogfeld Controller hinzufügen angezeigt wird, geben Sie dem Controller den Namen BooksController, und klicken Sie dann auf Hinzufügen.

    4. Wenn die Datei BooksController.cs geöffnet wird, ersetzen Sie den Code in der Datei durch Folgendes:

      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. Speichern und schließen Sie die Datei BooksController.cs .

  10. Erstellen Sie die Web-API-Anwendung, um nach Fehlern zu suchen.

Schritt 2: Hinzufügen des Windows Phone 8 Bookstore Catalog-Projekts

Der nächste Schritt dieses End-to-End-Szenarios besteht darin, die Kataloganwendung für Windows Phone 8 zu erstellen. Diese Anwendung verwendet die Vorlage Windows Phone Databound App für die Standard-Benutzeroberfläche und verwendet die Web-API-Anwendung, die Sie in Schritt 1 dieses Tutorials erstellt haben, als Datenquelle.

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Projektmappe BookStore , und klicken Sie dann auf Hinzufügen und dann auf Neues Projekt.

  2. Wenn das Dialogfeld Neues Projekt angezeigt wird, erweitern Sie Installiert, dann Visual C#, und Windows Phone.

  3. Markieren Sie Windows Phone Datengebundene App, geben Sie BookCatalog als Namen ein, und klicken Sie dann auf OK.

  4. Fügen Sie das Json.NET NuGet-Paket dem BookCatalog-Projekt hinzu:

    1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Verweise für das Projekt BookCatalog , und klicken Sie dann auf NuGet-Pakete verwalten.
    2. Wenn das Dialogfeld NuGet-Pakete verwalten angezeigt wird, erweitern Sie den Abschnitt Online , und heben Sie nuget.org hervor.
    3. Geben Sie Json.NET in das Suchfeld ein, und klicken Sie auf das Suchsymbol.
    4. Markieren Sie Json.NET in den Suchergebnissen, und klicken Sie dann auf Installieren.
    5. Klicken Sie nach Abschluss der Installation auf Schließen.
  5. Fügen Sie das BookDetails-Modell dem BookCatalog-Projekt hinzu. enthält ein generisches Modell der Bookstore-Klasse:

    1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt BookCatalog , klicken Sie dann auf Hinzufügen, und klicken Sie dann auf Neuer Ordner.

    2. Nennen Sie den neuen Ordner Models.

    3. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Modelle , klicken Sie dann auf Hinzufügen, und klicken Sie dann auf Klasse.

    4. Wenn das Dialogfeld Neues Element hinzufügen angezeigt wird, geben Sie der Klassendatei den Namen BookDetails.cs, und klicken Sie dann auf Hinzufügen.

    5. Wenn die Datei BookDetails.cs geöffnet wird, ersetzen Sie den Code in der Datei durch Folgendes:

      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. Speichern und schließen Sie die Datei BookDetails.cs .

  6. Aktualisieren Sie die MainViewModel.cs-Klasse , um die Funktionalität für die Kommunikation mit der BookStore-Web-API-Anwendung einzuschließen:

    1. Erweitern Sie den Ordner ViewModels im Projektmappen-Explorer, und doppelklicken Sie dann auf die Datei MainViewModel.cs .

    2. Wenn die Datei MainViewModel.cs geöffnet wird, ersetzen Sie den Code in der Datei durch Folgendes: Beachten Sie, dass Sie den Wert der Konstante mit der apiUrl tatsächlichen URL Ihrer Web-API aktualisieren müssen:

      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. Speichern und schließen Sie die Datei MainViewModel.cs .

  7. Aktualisieren Sie die Datei MainPage.xaml , um den Anwendungsnamen anzupassen:

    1. Doppelklicken Sie im Projektmappen-Explorer auf die Datei MainPage.xaml .

    2. Wenn die Datei MainPage.xaml geöffnet wird, suchen Sie die folgenden Codezeilen:

      <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. Ersetzen Sie diese Zeilen durch Folgendes:

      <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. Speichern und schließen Sie die Datei MainPage.xaml .

  8. Aktualisieren Sie die Datei DetailsPage.xaml , um die angezeigten Elemente anzupassen:

    1. Doppelklicken Sie im Projektmappen-Explorer auf die Datei DetailsPage.xaml .

    2. Wenn die Datei DetailsPage.xaml geöffnet wird, suchen Sie nach den folgenden Codezeilen:

      <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. Ersetzen Sie diese Zeilen durch Folgendes:

      <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. Speichern und schließen Sie die Datei DetailsPage.xaml .

  9. Erstellen Sie die Windows Phone-Anwendung, um nach Fehlern zu suchen.

Schritt 3: Testen der End-to-End-Lösung

Wie im Abschnitt Voraussetzungen dieses Tutorials erwähnt, müssen Sie beim Testen der Konnektivität zwischen web-API und Windows Phone 8-Projekten auf Ihrem lokalen System die Anweisungen im Artikel Verbinden des Windows Phone 8 Emulators mit Web-API-Anwendungen auf einem lokalen Computer befolgen, um Ihre Testumgebung einzurichten.

Nachdem Sie die Testumgebung konfiguriert haben, müssen Sie die Windows Phone Anwendung als Startprojekt festlegen. Markieren Sie hierzu die BookCatalog-Anwendung im Projektmappen-Explorer, und klicken Sie dann auf Als Startprojekt festlegen:

Screenshot des Fensters des Projektmappen-Explorers mit den Menüoptionen zum Festlegen der Windows Phone-Anwendung in der Option
Klicken Sie auf das Bild, um sie zu erweitern.

Wenn Sie F5 drücken, startet Visual Studio sowohl den Windows Phone Emulator, der die Meldung "Bitte warten" anzeigt, während die Anwendungsdaten von Ihrer Web-API abgerufen werden:

Screenshot des Fensters des Projektmappen-Explorers, in dem der Telefonemulator angezeigt wird und der Titel
Klicken Sie auf das Bild, um sie zu erweitern.

Wenn alles erfolgreich ist, sollte der Katalog angezeigt werden:

Screenshot des Fensters
Klicken Sie auf das Bild, um sie zu erweitern.

Wenn Sie auf einen Buchtitel tippen, zeigt die Anwendung die Buchbeschreibung an:

Screenshot des Telefonemulators über dem Projektmappen-Explorer-Fenster mit einem Buchtitel und einer Beschreibung.
Klicken Sie auf das Bild, um sie zu erweitern.

Wenn die Anwendung nicht mit Ihrer Web-API kommunizieren kann, wird eine Fehlermeldung angezeigt:

Screenshot des Telefonemulators, der über dem Projektmappen-Explorer-Fenster mit einem
Klicken Sie auf das Bild, um sie zu erweitern.

Wenn Sie auf die Fehlermeldung tippen, werden alle weiteren Details zum Fehler angezeigt:

Screenshot des Telefonemulators im Dialogfeld
Klicken Sie auf das Bild, um sie zu erweitern.