共用方式為


從 Windows Phone 8 應用程式呼叫 Web API (C#)

作者:Robert McMurray

在本教學課程中,您將瞭解如何建立完整的端對端案例,其中包含提供書籍目錄給Windows Phone 8 個應用程式的 ASP.NET Web API應用程式。

概觀

ASP.NET Web API等 RESTful 服務藉由抽象化伺服器端和用戶端應用程式的架構,簡化開發人員的 HTTP 型應用程式建立。 Web API 開發人員只需要發佈其應用程式的必要 HTTP 方法, (例如:GET、POST、PUT、DELETE) 和用戶端應用程式開發人員只需要取用其應用程式所需的 HTTP 方法,而不是建立專屬通訊端型通訊協定。

在此端對端教學課程中,您將瞭解如何使用 Web API 來建立下列專案:

必要條件

  • 已安裝 Windows Phone 8 SDK 的 Visual Studio 2013
  • 已安裝 Hyper-V 的 64 位系統上的 Windows 8 或更新版本
  • 如需其他需求的清單,請參閱Windows Phone SDK 8.0下載頁面上的系統需求一節。

注意

如果您要測試 Web API 與本機系統上Windows Phone 8 個專案之間的連線能力,您必須遵循在本機電腦上將 Windows Phone 8 模擬器連線至 Web API 應用程式一文中的指示,以設定測試環境。

步驟 1:建立 Web API 書籍存放區專案

此端對端教學課程的第一個步驟是建立支援所有 CRUD 作業的 Web API 專案;請注意,您將在本教學課程的步驟 2中,將Windows Phone應用程式專案新增至此解決方案。

  1. 開啟Visual Studio 2013

  2. 按一下 [ 檔案]、[ 新增] 和 [ 專案]。

  3. 顯示 [ 新增專案 ] 對話方塊時,展開 [ 已安裝]、[ 範本]、[ Visual C#] 和 [ Web]。

    [新增專案] 對話方塊的螢幕擷取畫面,其中顯示功能表中的檔案路徑,並醒目提示建立新專案的步驟。
    按一下影像以展開
  4. 醒目提示 ASP.NET Web 應用程式,輸入BookStore以取得專案名稱,然後按一下 [確定]。

  5. 當 [ 新增 ASP.NET 專案 ] 對話方塊顯示時,請選取 Web API 範本,然後按一下 [ 確定]。

    [A P 點 NET 專案書籍存放區] 對話方塊的螢幕擷取畫面,其中顯示選取範本資料夾和核心參考的範本選項和核取方塊。
    按一下影像以展開
  6. 當 Web API 專案開啟時,請從專案移除範例控制器:

    1. 展開方案總管中的 Controllers 資料夾。
    2. 以滑鼠右鍵按一下 ValuesController.cs 檔案,然後按一下 [ 刪除]。
    3. 出現提示以確認刪除時,按一下 [ 確定 ]。
  7. 將 XML 資料檔案新增至 Web API 專案;此檔案包含書籍存放區目錄的內容:

    1. 以滑鼠右鍵按一下方案總管中的 App_Data 資料夾,然後按一下 [ 新增],然後按一下 [ 新增專案]。

    2. 顯示 [ 加入新專案 ] 對話方塊時,醒目提示 XML 檔案 範本。

    3. 將檔案 命名Books.xml,然後按一下 [ 新增]。

    4. 開啟 Books.xml 檔案時,請將檔案中的程式碼取代為 MSDN 上範例 books.xml 檔案中的 XML:

      <?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. 儲存並關閉 XML 檔案。

  8. 將書籍存放區模型新增至 Web API 專案;此模型包含書籍存放區應用程式的建立、讀取、更新和刪除 (CRUD) 邏輯:

    1. 以滑鼠右鍵按一下方案總管中的 Models 資料夾,然後按一下 [ 新增],然後按一下 [ 類別]。

    2. 顯示 [ 新增專案 ] 對話方塊時,將類別檔案命名為 BookDetails.cs,然後按一下 [ 新增]。

    3. 開啟 BookDetails.cs 檔案時,請將檔案中的程式碼取代為下列內容:

      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. 儲存並關閉 BookDetails.cs 檔案。

  9. 將書籍存放區控制器新增至 Web API 專案:

    1. 以滑鼠右鍵按一下方案總管中的 Controllers 資料夾,然後按一下 [ 新增],然後按一下 [ 控制器]。

    2. 顯示 [ 新增 Scaffold ] 對話方塊時,醒目提示 [Web API 2 控制器 - 空白],然後按一下 [ 新增]。

    3. 顯示 [ 新增控制器 ] 對話方塊時,將控制器命名為 BooksController,然後按一下 [ 新增]。

    4. 開啟 BooksController.cs 檔案時,請將檔案中的程式碼取代為下列內容:

      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. 儲存並關閉 BooksController.cs 檔案。

  10. 建置 Web API 應用程式以檢查錯誤。

步驟 2:新增Windows Phone 8 個書籍存放區目錄專案

此端對端案例的下一個步驟是建立Windows Phone 8 的目錄應用程式。 此應用程式會針對預設使用者介面使用Windows Phone Databound 應用程式範本,並使用您在本教學課程的步驟 1中建立的 Web API 應用程式作為資料來源。

  1. 以滑鼠右鍵按一下方案總管中的 BookStore 方案,然後按一下 [ 新增],然後按一下 [ 新增專案]。

  2. 顯示 [新增專案] 對話方塊時,展開 [已安裝],然後展開 [Visual C#],然後Windows Phone

  3. 醒目提示Windows Phone Databound App,輸入BookCatalog以取得名稱,然後按一下 [確定]。

  4. 將 Json.NET NuGet 套件新增至 BookCatalog 專案:

    1. 以滑鼠右鍵按一下方案總管中BookCatalog專案的[參考],然後按一下 [管理 NuGet 套件]。
    2. 顯示 [ 管理 NuGet 套件 ] 對話方塊時,展開 [ 線上 ] 區段,並反白 顯示 nuget.org
    3. 在搜尋欄位中輸入 Json.NET ,然後按一下搜尋圖示。
    4. 在搜尋結果中 反白顯示 Json.NET ,然後按一下 [ 安裝]。
    5. 安裝完成時,按一下 [ 關閉]。
  5. BookDetails 模型新增至 BookCatalog 專案;這包含書籍存放區類別的泛型模型:

    1. 以滑鼠右鍵按一下方案總管中的 BookCatalog 專案,然後按一下 [ 新增],然後按一下 [ 新增資料夾]。

    2. 將新資料夾命名為 Models

    3. 以滑鼠右鍵按一下方案總管中的 Models 資料夾,然後按一下 [ 新增],然後按一下 [ 類別]。

    4. 顯示 [ 新增專案 ] 對話方塊時,將類別檔案命名為 BookDetails.cs,然後按一下 [ 新增]。

    5. 開啟 BookDetails.cs 檔案時,請將檔案中的程式碼取代為下列內容:

      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. 儲存並關閉 BookDetails.cs 檔案。

  6. 更新 MainViewModel.cs 類別,以包含與 BookStore Web API 應用程式通訊的功能:

    1. 展開方案總管中的 ViewModels 資料夾,然後按兩下 MainViewModel.cs 檔案。

    2. 開啟 MainViewModel.cs 檔案時,請將檔案中的程式碼取代為下列專案;請注意,您必須使用 Web API 的實際 URL 來更新常數的值 apiUrl

      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. 儲存並關閉 MainViewModel.cs 檔案。

  7. 更新 MainPage.xaml 檔案以自訂應用程式名稱:

    1. 按兩下方案總管中的 MainPage.xaml 檔案。

    2. 開啟 MainPage.xaml 檔案時,請找出下列幾行程式碼:

      <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. 將這些行取代為下列專案:

      <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. 儲存並關閉 MainPage.xaml 檔案。

  8. 更新 DetailsPage.xaml 檔案以自訂顯示的專案:

    1. 按兩下方案總管中的 DetailsPage.xaml 檔案。

    2. DetailsPage.xaml 檔案開啟時,請找出下列幾行程式碼:

      <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. 將這些行取代為下列專案:

      <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. 儲存並關閉 DetailsPage.xaml 檔案。

  9. 建置Windows Phone應用程式以檢查錯誤。

步驟 3:測試端對端解決方案

如本教學課程的必要條件一節所述,當您在本機系統上測試 Web API 與 Windows Phone 8 個專案之間的連線時,您必須遵循在本機電腦上將 Windows Phone 8 模擬器連線至 Web API 應用程式一文中的指示來設定測試環境。

設定測試環境之後,您必須將Windows Phone應用程式設定為啟動專案。 若要這樣做,請在方案總管中醒目提示 BookCatalog 應用程式,然後按一下 [ 設定為啟始專案]:

方案總管視窗的螢幕擷取畫面,其中顯示功能表選項,以在 [設定為啟動專案] 選項中設定 Windows Phone 應用程式。
按一下影像以展開

當您按下 F5 時,Visual Studio 會啟動Windows Phone模擬器,這會在應用程式資料從 Web API 擷取時顯示「請等候」訊息:

方案總管視窗的螢幕擷取畫面,其中顯示手機模擬器快顯,顯示 [書籍市集] 標題和 [請等候] 訊息。
按一下影像以展開

如果一切都成功,您應該會看到目錄顯示:

方案總管視窗的螢幕擷取畫面,其中顯示手機模擬器,其中顯示目錄中標題的書籍市集。
按一下影像以展開

如果您點選任何書籍標題,應用程式會顯示書籍描述:

手機模擬器在方案總管視窗上的螢幕擷取畫面,其中顯示書籍標題和描述。
按一下影像以展開

如果應用程式無法與您的 Web API 通訊,將會顯示錯誤訊息:

手機模擬器的螢幕擷取畫面,顯示在方案總管視窗上,顯示「發生錯誤」和錯誤的簡短描述。
按一下影像以展開

如果您點選錯誤訊息,將會顯示有關錯誤的任何其他詳細資料:

手機模擬器的螢幕擷取畫面,顯示 [方案總管] 對話方塊上的 [發生錯誤],後面接著錯誤的詳細資料。
按一下影像以展開