1. 程式人生 > >ASP.NET Web API(MVC API)

ASP.NET Web API(MVC API)

資源 應該 stack 文本格式 開發 oid itl 行操作 pac

  ASP.NET Web API是??一個框架,可以很容易構建達成了廣泛的HTTP服務客戶端,包括瀏覽器和移動設備。是構建RESTful應用程序的理想平臺的.NET框架。

  上面是微軟對Web API給出的定義,其中包含兩個關鍵字:HTTP和RESTful,其實從這一方面,大家就可以看出Web API和它的同胞兄弟:WebService和WCF有些不同了。

HTTP

技術分享圖片

  對於HTTP大家都不是很陌生,因為我們每天瀏覽網頁填寫的URL就是HTTP開頭,但只是知道有這個東西,確沒有想過它是什麽,就好像我們對世間萬物有著模糊的認識,但認識東西的確很少。

  也可以從另一方面去理解,曾經看一個電視節目,有個嘉賓在錄制的過程中,突然擡起頭對著天花板仰望,然後主持人很驚訝問他在幹嗎?他說:我在思考宇宙有沒有盡頭?主持人接著問:那宇宙有沒有盡頭?他淡然的回答道:有就有,沒有就沒有。當然觀眾和主持人都笑作一團,你會笑嗎?透過現象看本質,其實這個思想和老莊的思想很合拍,扯遠了。

HTTP即超文本傳送協議。

超文本傳輸協議 (HTTP-Hypertext transfer protocol) 是一種詳細規定了瀏覽器和萬維網服務器之間互相通信的規則,通過因特網傳送萬維網文檔的數據傳送協議。

  從定義中看出HTTP是一種協議,超文本傳輸協議,那什麽是超文本?和我們所說的富文本有些區別,超文本也是一種文本格式,那可以把它看成是文本與文本之間關聯而組成的網狀文本,有點類似於面向對象中對象的集合,雖然是對象的集合,但本身也是一個對象。

  HTTP協議有下面三個基本特點:

  • 簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶與服務器聯系的類型不同。由於HTTP協議簡單,使得HTTP服務器的程序規模小,因而通信速度很快。
  • 靈活:HTTP允許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type加以標記。
  • 無狀態:無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味著如果後續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送的數據量增大。

  相對於Web API來說,HTTP不只是為了生成Web頁面,它也是一個強大的平臺建設公開服務和數據的API。HTTP是簡單、 靈活和無處不在,因此幾乎任何平臺都可以有一個HTTP庫,因此,HTTP服務可以到達範圍廣泛的客戶端,包括瀏覽器、移動設備和傳統的桌面應用程序。

RESTful

  RESTful架構概念是Fielding提出的,Fielding這號人物就是上面HTTP協議的主要設計者之一。我們先看下RESTful這個詞,ful是跟在名詞之後,表示程度,什麽什麽的,例如helpful樂於助人的,因此我們可以看出符合REST的架構就可以稱為RESTful,接著我們看下REST,全稱為“Representational State Transfer”,意為“表現層狀態轉化”。

在符合架構原理的前提下,理解和評估以網絡為基礎的應用軟件的架構設計,得到一個功能強、性能好、適宜通信的架構。  -Fielding

  這是Fielding在論文中所提到的,對於REST雖說是架構,但如果深入一點,就像是HTTP協議一樣,可以看成一種規則或是協議。我們從一個地點到另一個地點,可以坐汽車、高鐵、飛機等,對於REST就像是其中的一種交通方式,但REST的根本是HTTP協議,也就是說REST是基於HTTP協議的,這點就像坐汽車必須要有公路,坐高鐵必須要有鐵路是一樣的道理,有時候為什麽選用REST,就像我們從南京到徐州,選擇坐高鐵而不選擇坐飛機一樣。

  上面這個比喻可能不太恰當,但是思想都是相同的,如果有可能的話可以看下一些哲學方面的書,像莊子的道德經,畢竟編程是哲學或是藝術的另一類體現,又扯遠了。

  “Representational State Transfer”我們分解下:

  • Representational 表現層:表現層表現什麽,應該呈現資源(Resources),一個圖片、一段文字、一個文件都成為資源,每個資源都用一個URI(統一資源定位符)指向它,表現層就是調用URI把資源呈現出來,而且只是呈現,不做其他操作。舉個例子:有些網址最後的".html"後綴名是不必要的,因為這個後綴名表示格式,屬於"表現層"範疇,而URI應該只代表"資源"的位置。它的具體表現形式,應該在HTTP請求的頭信息中用Accept和Content-Type字段指定,這兩個字段才是對"表現層"的描述。
  • State Transfer 狀態轉化:訪問一個網站,就表示客戶端和服務器發生一次交互行為,在這個過程中,就不發生數據和狀態的轉化,上面說到HTTP協議具有無狀態性,如果客戶端操作服務器,必須要狀態轉化,這個體現在表現層上,所以叫“表現層狀態轉化”。

  通過上面的理解,可以總結下什麽是RESTful架構:

  1. 每一個URI代表一種資源。
  2. 客戶端和服務器之間,傳遞這種資源的某種表現層。
  3. 客戶端通過四個HTTP動詞(PUT、GET、POST和DELETE),對服務器端資源進行操作,實現"表現層狀態轉化"。

創建Web API

  關於Web API的實現方式,.net提供了一套機制就是ASP.NET MVC API,類似MVC的方式,實現起來很簡單,也不需要你去關註HTTP和RESTful的一些東西,當你去新建項目的時候,一切東西.net都幫你搞定了,是好還是不好?只能呵呵笑過。

  下面我們就一步一步的創建一個ASP.NET MVC API。

  1,新建ASP.NET MVC WebMvc的ApiDemo程序,選擇Web API模板類型。

技術分享圖片

技術分享圖片

  2,創建News模型,雖然創建的是MVC項目,但是我們一般只用到控制器和模型。

    public class News
    {
        /// <summary>
        /// 新聞ID
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 新聞標題
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// 新聞內容
        /// </summary>
        public string Content { get; set; }
        /// <summary>
        /// 新聞作者
        /// </summary>
        public string Author { get; set; }
        /// <summary>
        /// 發布新聞時間
        /// </summary>
        public DateTime CreateTime { get; set; }
    }

  3,創建數據模擬類NewsRepository,用於查詢數據。

    public class NewsRepository
    {
        public IEnumerable<News> GetAllNews()
        {
            News[] news = new News[] 
            { 
                new News { Id = 1, Title="新聞標題1", Content="新聞內容1", Author="xishuai", CreateTime=DateTime.Now }, 
                new News { Id = 2, Title="新聞標題2", Content="新聞內容2", Author="xishuai", CreateTime=DateTime.Now }, 
                new News { Id = 3, Title="新聞標題2", Content="新聞內容3", Author="xishuai", CreateTime=DateTime.Now }
            };
            return news;
        }
    }

  4,創建NewsController控制器,註意的是:新建控制器的時候,模板選擇“空 API 控制器”,與MVC控制器不同的是,API控制器繼承ApiController基類。在我們新建ApiDemo的MVC項目的時候,自動生成了一個ValuesController API控制器,打開後我們發現,有很多自動生成的方法,請求方式就是我們上面說GET、POST、PUT和DELETE的四種HTTP請求方式,我們這邊做一個Get的,獲取全部新聞或是指定新聞ID獲取,返回結果格式為XML。

    public class NewsController : ApiController
    {
        /// <summary>
        /// GET獲取全部新聞
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public HttpResponseMessage GetAllNews()
        {
            var news = new NewsRepository().GetAllNews();
            return new HttpResponseMessage()
            {
                RequestMessage = Request,
                Content = new XmlContent(SimpleXmlConverter.ToXmlDocument<News>(news, "NewsRoot"))
            };
        }

        /// <summary>
        /// GET獲取指定ID新聞
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        [HttpGet]
        public HttpResponseMessage GetNewsByID(int ID)
        {
            var news = new NewsRepository().GetAllNews().Where((p) => p.Id == ID);
            return new HttpResponseMessage()
            {
                RequestMessage = Request,
                Content = new XmlContent(SimpleXmlConverter.ToXmlDocument<News>(news, "NewsRoot"))
            };
        }
    }

  這裏面主要用到兩個轉化類:XmlContent和SimpleXmlConverter,有關這兩個類的詳細代碼可以下載Demo看下。

  • XmlContent:XML格式輸出,參考http://stackoverflow.com/questions/15366096/how-to-return-xml-data-from-a-web-api-method。
  • SimpleXmlConverter:實體集合轉化XDocument、XElement、XDocument,參考http://www.cnblogs.com/jasenkin/archive/2012/02/19/simpe_xml_converter.html,裏面的代碼稍微修改了下。

  5,路由配置,Web API和MVC的路由配置很相似,主要區別是Web API使用HTTP方法而不是URI路徑來選擇動作,路由文件WebApiConfig,如下:

config.Routes.MapHttpRoute
(
   name: "DefaultApi",
   routeTemplate: "api/{controller}/{action}/{id}",
   defaults: new { id = RouteParameter.Optional }
);

  

 其實寫到這裏創建Web API的代碼就差不多了,當然復雜的操作可以擴充,用.net開發就是這麽簡單,只要完成業務邏輯就行了,呵呵。

調用Web API

  調用Web API有很多種方式,js可以調用,就像我們寫MVC請求數據一樣,這種是同一域下調用,Web API也是這種方式就沒什麽意思了,如果使用js調用就必須跨域操作,這邊我們使用HttpClient的方式。

  1,新建控制臺應用程序-ClientDemo。

技術分享圖片

  2,安裝Web API 客戶端庫,工具-程序包管理器-程序包管理控制平臺,輸入命令:Install-Package Microsoft.AspNet.WebApi.Client

  上面新建的ClientDemo項目.net framework版本是4.0,安裝HttpClient的時候報下面錯誤:

技術分享圖片

  .net framework版本改為4.5就安裝成功了,難道HttpClient只支持4.5以上?查了下MSDN,HttpClient確實只支持.net framework4.5,難道以前程序如果使用HttpClient要把.net framework改成4.5?有點郁悶。

技術分享圖片

  4,創建HttpClient,先貼下代碼:

        static void Main(string[] args)
        {
            RunAsync().Wait();
        }

        static async Task RunAsync()
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:8077/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

                string xmlString = await client.GetStringAsync("api/News/GetAllNews");
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xmlString);
                XmlNodeList nodeList = xmlDoc.GetElementsByTagName("News");
                foreach (XmlNode node in nodeList)
                {
                    Console.WriteLine("新聞ID:" + node.SelectSingleNode("Id").InnerText);
                    Console.WriteLine("新聞標題:" + node.SelectSingleNode("Title").InnerText);
                    Console.WriteLine("新聞內容:" + node.SelectSingleNode("Content").InnerText);
                    Console.WriteLine("作者:" + node.SelectSingleNode("Author").InnerText);
                    Console.WriteLine("新聞發布時間:" + node.SelectSingleNode("CreateTime").InnerText);
                    Console.WriteLine("======================");
                }
                Console.ReadKey();
            }
        }

 

Main 函數調用一個名為RunAsync的異步方法,然後會阻止,直到RunAsync完成。許多的HttpClient方法是異步,因為他們執行網絡 i/o 操作。MediaTypeWithQualityHeaderValue是定義傳輸格式,如果使用json則為“application/json”,這邊要與Web API格式一致,XML獲取使用的是GetStringAsync方法,然後轉換為XmlDocument,網上找了一種GetStreamAsync方法獲取,通過Stream轉化為字符串,但是轉化後的字符串為空。

  上面調用Web API的是獲取全部新聞,如果調用通過新聞ID獲取新聞,GetStringAsync的方法參數只需要改為“api/News/GetNewsByID/新聞ID”就可以了。

  5,關於Web API的發布問題,這個問題花了不少時間,一個一個問題出現及解決,首先我們先不急著調用,先發布瀏覽,如果瀏覽器瀏覽沒問題的話再調用。Web API的發布和MVC差不多,需要註意下面幾點:

  • 文件權限別忘了配置,要配置every one。
  • 應用程序池選擇“ASP.NET v4.0 DefaultAppPool”。
  • 選擇應用程序池之後要配置“ISAPI 和 CGI 限制”的4.0版本設置為允許,要不然出現“由於 Web 服務器上的“ISAPI 和 CGI 限制”列表設置,無法提供您請求的頁面。”的錯誤。
  • “Newtonsoft.Json”文件引用。
  • “An error has occurred.Multiple actions were found that match the request”,這個錯誤信息是Web API的路由沒有配置好,要檢查下。
  • “Response status code does not indicate success: 404 (Not Found)”,這個錯誤信息也是路由問題。
  • “Response status code does not indicate success: 500 (Internal Server Error).”,這個是服務器問題,也就是Web API的代碼問題。

運行截圖及Demo下載

  Web API瀏覽器請求截圖:

技術分享圖片

  Web API發布運行截圖:

技術分享圖片

  客戶端調用運行截圖:

技術分享圖片

  Demo下載地址:http://pan.baidu.com/s/1gdopRub

  HTTP請求的四種方法(PUT、GET、POST和DELETE)本篇只是講到GET,HTTP的數據傳輸格式(json、xml等)也只是說了XML,但都是大同小異,舉一反三可得。

 

ASP.NET Web API(MVC API)