Self Host模式下的ASP. NET Web API是如何進行請求的監聽與處理的?
構成ASP.NET Web API核心框架的消息處理管道既不關心請求消息來源於何處,也不需要考慮響應消息歸於何方。當我們采用Web Host模式將一個ASP.NET應用作為目標Web API的宿主時,實際上是由ASP.NET管道解決了這兩個問題。具體來說,ASP.NET自身的URL路由係統借助於HttpControllerHandler這個自定義的HttpHandler實現了ASP.NET管道和ASP.NET Web API管道之間的“連通”,但是在Self Host寄宿模式下,請求的監聽、接收和響應又是如何實現的呢?[本文已經同步到《How ASP.NET Web API Works?》]
目錄
一、HttpBinding模型
Binding模型
HttpBinding
實例演示:直接利用HttpBinding進行請求的接收和響應
二、HttpSelfHostServer
HttpSelfHostConfiguration
HttpSelfHostServer與消息處理管道
實例演示:創建自定義HttpServer模擬HttpSelfHostServer的工作原理
一、HttpBinding模型
和WCF服務一樣,我們可以采用Self Host模式將Web API寄宿於任何一種類型的托管應用程序下,宿主可以是一個Windows Form應用、WPF應用、控製台應用以及Windows Service。Self Host模式下的WCF和ASP.NET Web API不僅外在表現形式極為相似,其實在內部實現原理上也是一致的。
Binding模型
對於WCF具有基本了解的讀者應該都知道,它是一個基於消息的分布式通信框架,消息交換借助於客戶端和服務端對等的終結點(Endpoint)來完成,而終結點由經典的ABC(Address、Binding、Contract)三元素組成。WCF同樣具有一個處理消息的管道,這個管道是一組Channel的有序組合,WCF下的Channel相對於ASP.NET Web API下的HttpMessageHandler。
WCF的消息處理管道的締造者是作為終結點三要素之一的Binding。Binding不僅僅為服務端創建用於接收請求回複響應的管道,同時也為客戶端創建發送請求接收響應的管道。Binding模型本身也相對比較複雜,所以我們不可能對其進行詳細討論。如果讀者對此比較感興趣,可以參閱《WCF的綁定模型》。由於ASP.NET Web API隻是利用HttpBinding創建服務端消息處理管道,所以我們隻討論Binding的服務端模型。
從結構上講,一個Binding是若幹BindingElement對象的有序組合。對於最終創建的消息處理管道來說,每個Channel都對應著一個BindingElement。BindingElement並非直接創建對應的Channel,由它直接創建的實際上是一個名為ChannelListener的對象,Channel由ChannelListener創建。右圖基本揭示了Binding的服務端模型。
顧名思義,ChannelListener用於請求的監聽。當Binding對象開啟(調用其Open方法)時,每個BindingElement會創建各自的ChannelListener。這些ChannelListener按照對應BindingElement的順序連接成串,位於底部(麵向傳輸層)的ChannelListener被綁定到某個端口進行請求的監聽。一旦探測到抵達的請求,它會利用由所有ChannelListener創建的Channel組成的管道來接收並處理該請求。對於最終需要返回的響應消息,則按照從上到下的順序被這個管道進行處理並最終返回給客戶端。
對於這個由Channel組成消息處理管道來說,有兩種類型的Channel是必不可少的。一種是麵向傳輸層用於發送和接收消息的TransportChannel,另一種被稱為MessageEncodingChannel則負責對接收的消息實施解碼並對發送的消息實施編碼。TransportChannel由TransportChannelListener創建,而後者由TransportBindingElement創建。與之類似,MessageEncodingBindingElement是MessageEncodingChannelListener的創建者,而後者又是MessageEncodingChannel的創建者。
如果采用Self Host寄宿模式,請求的監聽是由一個類型為HttpBinding的Binding對象創建的ChannelListener管道來完成的,由它創建的管道實現了針對請求的接收和針對響應的回複。HttpBinding類型定義在“System.Web.Http.SelfHost.Channels”命名空間下,我們接下來對它進行詳細講述。
HttpBinding
Binding存在的目的在於創建用於處理和傳輸消息的信道棧,組成信道棧的每一個Channel均對應著一個BindingElement,所以Binding本身處理消息的能力由其BindingElement的組成來決定,我們可以通過分析BindingElement的組成來了解消息最終是如何處理的。現在我們就來討論一下ASP.NET Web API在Self Host模式下使用的HttpBinding由哪些BindingElement構成。
如左圖所示,HttpBinding僅僅由兩種必需的BindingElement構成,TransportBindingElement的類型決定於最終采用的傳輸協議。如果采用單純的HTTP協議,采用的TransportBindingElement是一個HttpTransportBindingElement對象。在采用HTTPS協議的情況下,TransportBindingElement的類型是HttpsTransportBindingElement。
我們現在著重來分析與消息編碼/解碼相關的BindingElement,從圖3-11可以看出這是一個HttpMessageEncodingBindingElement對象(HttpMessageEncodingBindingElement是一個定義在程序集“System.Web.Http.SelfHost.dll”中的內部類型),它最終會創建一個MessageEncoder對象完成針對消息的編碼/解碼工作。
ASP.NET Web API分別利用 HttpRequestMessage和HttpResponseMessage對象表示消息處理管道處理的請求和響應,而WCF消息處理管道的請求和響應均是一個Message對象(Message是定義在命名空間“System.ServiceModel.Channels”下的一個抽象類型)。經過HttpMessageEncoder解碼後的Message對象會轉成一個HttpRequestMessage對象並傳入ASP.NET Web API消息處理管道進行處理,由此管道返回的HttpResponseMessage對象需要轉換成一個Message對象並由HttpMessageEncoder根據需求進行解碼。
這個具體的消息實際上是一個HttpMessage對象,HttpMessage繼承自抽象類Message,它是一個定義在程序集“System.Web.Http.SelfHost.dll”中的內部類型。如下麵的代碼片斷所示,HttpMessage實際上是對一個HttpRequestMessage或者HttpResponseMessage對象的封裝,兩個方法GetHttpRequestMessage和GetHttpResponseMessage分別用於提取被封裝的HttpRequestMessage和HttpResponseMessage對象。
1: internal sealed class HttpMessage : Message
2: {
3: //其他成員
4: public HttpMessage(HttpRequestMessage request);
5: public HttpMessage(HttpResponseMessage response);
6:
7: public HttpRequestMessage GetHttpRequestMessage(bool extract);
8: public HttpResponseMessage GetHttpResponseMessage(bool extract);
9: }
這兩個方法均具有一個布爾類型的參數extract,它表示是否“抽取”被封裝的HttpRequestMessage/HttpResponseMessage對象。如果指定的參數值為True,方法執行之後被封裝的HttpRequestMessage/HttpResponseMessage對象會從HttpMessage對象中抽取出來,所以再次調用它們會返回Null。
再次將我們的關注點拉回到由HttpBinding創建的消息處理管道上。當我們開啟HttpBinding後,它利用創建的ChannelListener管道監聽請求。一旦探測到抵達的請求後,基於HTTP/HTTPS協議的TransportChannel會負責接收請求。接收的二進製數據會由MessageEncoder解碼後生成一個HttpRequestMessage對象,該對象進而被封裝成一個HttpMessage對象,傳入消息處理管道的HttpRequestMessage是直接通過調用GetHttpRequestMessage方法從該HttpMessage對象中提取的。
當ASP.NET Web API消息處理管道完成了請求的處理並最終輸出一個HttpResponseMessage對象後,該對象同樣先被封裝成一個HttpMessage對象。在通過傳輸層將響應返回給客戶端之前,需要利用MessageEncoder對其進行編碼,而解碼的內容實際上就是調用GetHttpResponseMessage方法提取的HttpResponseMessage對象。
實例演示:直接利用HttpBinding進行請求的接收和響應
當我們采用Self Host寄宿模式將一個非Web應用程序作為目標Web API的宿主時,最終網絡監聽任務實際上是由HttpBinding創建的ChannelListener管道來完成的,而ChannelListener管道創建的消息處理管道最終實現了對請求的接收和對響應的發送。為了讓讀者對此具有深刻的認識,我們通過一個簡單的實例來演示如何直接使用HttpBinding實現對請求的監聽、接收和響應。
我們創建一個空的控製台程序作為監聽服務器,它相當於Self Host寄宿模式下的宿主程序。如下麵的代碼片斷所示,我們創建了一個HttpBinding,並指定監聽地址("https://127.0.0.1:3721")調用其BuildChannelListener<IReplyChannel>方法創建了一個ChannelListener管道(返回的是組成管道的第一個ChannelListener對象)。在調用Open方法開啟該ChannelListener管道之後,我們調用其AcceptChannel方法創建了消息處理管道,返回的是組成管道的第一個Channel對象。在Open方法將其開啟後,我們在一個While循環中調用Channel對象的ReceiveRequest方法進行請求的監聽和接收。
1: class Program
2: {
3: static void Main(string[] args)
4: {
5: Uri listenUri = new Uri("https://127.0.0.1:3721");
6: Binding binding = new HttpBinding();
7:
8: //創建、開啟信道監聽器
9: IChannelListener<IReplyChannel> channelListener = binding.BuildChannelListener<IReplyChannel>(listenUri);
10: channelListener.Open();
11:
12: //創建、開啟回複信道
13: IReplyChannel channel = channelListener.AcceptChannel(TimeSpan.MaxValue);
14: channel.Open();
15:
16: //開始監聽
17: while (true)
18: {
19: //接收輸出請求消息
20: RequestContext requestContext = channel.ReceiveRequest(TimeSpan.MaxValue);
21: PrintRequestMessage(requestContext.RequestMessage);
22: //消息回複
23: requestContext.Reply(CreateResponseMessage());
24: }
25: }
26: }
對於成功接收的消息,我們調用具有如下定義的PrintRequestMessage方法將相關的信息打印在控製台上。通過上麵的介紹我們知道這個接收到的消息實際上是一個HttpMessage對象,由於這是一個內部類型,所以我們隻能以反射的方式調用其GetHttpRequestMessage方法獲取被封裝的HttpRequestMessage對象。在得到表示請求的HttpRequestMessage對象之後,我們將請求地址和所有報頭輸出到控製台上。
1: private static void PrintRequestMessage(Message message)
2: {
3: MethodInfo method = message.GetType().GetMethod("GetHttpRequestMessage");
4: HttpRequestMessage request = (HttpRequestMessage)method.Invoke(message, new object[]{false});
5:
6: Console.WriteLine("{0, -15}:{1}", "RequestUri", request.RequestUri);
7: foreach (var header in request.Headers)
8: {
9: Console.WriteLine("{0, -15}:{1}", header.Key, string.Join("," ,header.Value.ToArray()));
10: }
11: }
在對請求進行處理之後,我們需要創建一個Message對象對該請求予以響應,響應消息的創建是通過CreateResponseMessage方法完成的。如下麵的代碼片斷所示,我們首先創建了一個響應狀態為“200, OK”的HttpResponseMessage對象,並將其表示主體內容的Content屬性設置為一個ObjectContent<Employee>對象。由於我們采用MediaTypeFormatter類型為JsonMediaTypeFormatter,指定的Employee對象會以JSON格式進行序列化。最終的響應消息依然是一個HttpMessage對象,它是對我們創建的HttpResponseMessage對象的封裝。限於“內部類型”的限製,我們也不得不采用反射的方式來創建這麼一個HttpMessage對象。
1: private static Message CreateResponseMessage()
2: {
3: HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
4: Employee employee = new Employee("001","Zhang San","123456","zhangsan@gmail.com");
5: response.Content = new ObjectContent<Employee>(employee, new JsonMediaTypeFormatter());
6:
7: string httpMessageTypeName = "System.Web.Http.SelfHost.Channels.HttpMessage, System.Web.Http.SelfHost";
8: Type httpMessageType = Type.GetType(httpMessageTypeName);
9: return (Message)Activator.CreateInstance(httpMessageType, new object[] { response });
10: }
11:
12: public class Employee
13: {
14: public string Id { get; set; }
15: public string Name { get; set; }
16: public string PhoneNo { get; set; }
17: public string EmailAddress { get; set; }
18:
19: public Employee(string id, string name, string phoneNo, string emailAddress)
20: {
21: this.Id = id;
22: this.Name = name;
23: this.PhoneNo = phoneNo;
24: this.EmailAddress = emailAddress;
25: }
26: }
當我們直接運行該程序後,實際上就已經啟動了針對基地址"https://127.0.0.1:3721"的監聽器。現在我們通過瀏覽器對這個監聽器發起請求,為了使請求更像一個針對Web API的調用,我們將請求地址設置為“https://127.0.0.1:3721/employees/001”(看起來好像是獲取某個編號為001的員工信息)。如右圖所示,通過瀏覽器發送的請求相關信息會顯示在控製台上,而瀏覽器上也會顯示基於JSON格式的員工信息。
二、HttpSelfHostServer
ASP.NET Web API的Self Host寄宿模式是通過一個System.Web.Http.SelfHost.HttpSelfHostServer對象來完成的,那麼HttpSelfHostServer與上麵介紹的HttpBinding又有何關係呢?HttpSelfHostServer與ASP.NET Web API的消息處理管道又是如何集成的呢?
如下麵的代碼片斷所示,HttpSelfHostServer其實是HttpServer的子類,所以在Self Host模式下HttpSelfHostServer本身就是消息管道的組成部分。換句話說,以HttpSelfHostServer為“龍頭”的消息處理管道本身具有請求監聽、接收、處理和響應的能力。
1: public sealed class HttpSelfHostServer : HttpServer
2: {
3: public HttpSelfHostServer(HttpSelfHostConfiguration configuration);
4: public HttpSelfHostServer(HttpSelfHostConfiguration configuration, HttpMessageHandler dispatcher);
5:
6: public Task OpenAsync();
7: public Task CloseAsync();
8:
9: protected override void Dispose(bool disposing);
10: }
ASP.NET Web API的消息處理管道的配置利用通過HttpServer的Configuration屬性表示的HttpConfiguration對象來完成,對於HttpSelfHostServer來說,它的Configuration屬性返回一個HttpSelfHostConfiguration對象(HttpSelfHostConfiguration類型定義在 “System.Web.Http.SelfHost” 命名空間下)。如上麵的代碼片斷所示,當我們調用構造函數創建一個HttpSelfHostServer對象時,需要通過參數指定此HttpSelfHostConfiguration。
HttpSelfHostConfiguration
如下麵的代碼片斷所示,HttpSelfHostConfiguration直接繼承自HttpConfiguration。我們在創建一個HttpSelfHostConfiguration對象的時候需要指定一個Uri對象作為監聽基地址,這個地址通過隻讀屬性BaseAddress返回。
1: public class HttpSelfHostConfiguration : HttpConfiguration
2: {
3: public HttpSelfHostConfiguration(Uri baseAddress);
4:
5: public Uri BaseAddress { get; }
6: public HostNameComparisonMode HostNameComparisonMode { get; set; }
7: public TransferMode TransferMode { get; set; }
8:
9: public int MaxBufferSize { get; set; }
10: public int MaxConcurrentRequests { get; set; }
11: public long MaxReceivedMessageSize { get; set; }
12:
13: public TimeSpan ReceiveTimeout { get; set; }
14: public TimeSpan SendTimeout { get; set; }
15:
16: public HttpClientCredentialType ClientCredentialType { get; set; }
17: public UserNamePasswordValidator UserNamePasswordValidator { get; set; }
18: public X509CertificateValidator X509CertificateValidator { get; set; }
19: }
由於Self Host寄宿模式下請求的監聽、接收和響應基本上全部是通過HttpBinding實現的,所以定義在HttpSelfHostConfiguration中的眾多屬性實際上基本都用於對創建的HttpBinding進行配置。從如下給出的代碼片斷可以看出HttpBinding類型與HttpSelfHostConfiguration具有類似的屬性定義。
1: public abstract class Binding : IDefaultCommunicationTimeouts
2: {
3: //其他成員
4: public TimeSpan ReceiveTimeout { get; set; }
5: public TimeSpan SendTimeout { get; set; }
6: }
7:
8: public class HttpBinding : Binding, IBindingRuntimePreferences
9: {
10: //其他成員
11: public HostNameComparisonMode HostNameComparisonMode { get; set; }
12: public TransferMode TransferMode { get; set; }
13:
14: public long MaxBufferPoolSize { get; set; }
15: public int MaxBufferSize { get; set; }
16: public long MaxReceivedMessageSize { get; set; }
17:
18: public HttpBindingSecurity Security { get; set; }
19: }
由於Binding在WCF是一個核心組件,其設計本身相對複雜,要深入了解定義在HttpBinding中的這些屬性需要相關的背景知識。篇幅所限,我們不能因為這些屬性將Binding相關的內容全部搬過來,所以在這裏我們僅僅通過下表對它們進行概括性的介紹。
屬性 |
描述 |
HostNameComparisonMode |
如果請求URL沒有指定服務器的IP地址而是主機名稱,當從URL提取主機名稱後會按照相應的比較模式來最終確定匹配的主機名。該屬性的類型為System.ServiceModel.HostNameComparisonMode枚舉,用以確定主機名比較模式。 |
TransferMode
|
消息傳輸具有Streamed和Buffered兩種模式,前者以流的形式進行消息傳輸,後者則將整個消息的內容先保存於內存緩衝區後一並傳輸。該屬性類型為System.ServiceModel.TransferMode枚舉,用以控製針對請求消息和響應消息的傳輸模式。在默認情況下,請求消息和響應消息均以Buffered模式進行傳輸。MaxBufferSize屬性表示在采用Buffered模式下消息最大緩衝大小,默認值為65536(0x10000)。 |
MaxConcurrentRequests
|
這兩個是針對請求的限製,分別表示運行的最大並發訪問量和請求消息允許的最大尺寸。兩者的默認值分別為100和65536(0x10000)。值得一提的是MaxConcurrentRequests針對最大並發請求的限製是針對單個處理器設定的,對於多處理器或者多核處理來說,應該乘以處理器的數量。 |
ReceiveTimeout
|
這兩個屬性分別表示接收請求消息和發送響應消息的超時時限,默認值分別為10分鍾和1分鍾。 |
ClientCredentialType
|
這是三個與安全認證相關的屬性。ClientCredentialType表示客戶端采用的用戶憑證類型,而UserNamePasswordValidator和X509CertificateValidator屬性值分別在用戶憑證為“用戶名+密碼”和“X.509證書”的情況下實施認證。 |
HttpSelfHostServer與消息處理管道
在采用Self Host模式寄宿Web API時,我們會根據指定的監聽基地址創建一個HttpSelfHostConfiguration對象,然後據此創建HttpSelfHostServer。當我們調用方法OpenAsync開啟它時,HttpSelfHostServer會創建一個HttpBinding對象,並根據指定的HttpSelfHostConfiguration對其作相應的設置。隨後HttpBinding會針對指定的監聽地址創建一個ChannelListener管道,並調用其BeginOpen方法以異步的方式開啟。除了OpenAsync方法外,HttpSelfHostServer還定義了一個CloseAsync方法使我們可以以異步的方式關閉已經開啟的ChannelListener管道。
一旦ChannelListener管道被成功開啟後,它便綁定到指定的監聽地址進行請求的監聽。當抵達的請求被探測到,它會利用創建的消息處理管道來接收該請求。通過上麵對HttpBinding的介紹我們知道,接收到的二進製數據經過解碼之後會生成一個HttpMessage對象,後者是對一個HttpRequestMessage的封裝。
接下來HttpSelfHostServer從生成的HttpMessage中提取被封裝的HttpRequestMessage對象,並直接分發給後續的HttpMessageHandler作進一步處理。對於最終返回的表示響應的HttpResponseMessage對象,HttpSelfHostServer將其封裝成一個HttpMessage對象並利用消息處理管道返回給客戶端。在通過傳輸層發送響應消息之前,HttpMessage會先編碼。通過上麵的介紹我們知道整個編碼工作完全是針對被HttpMessage封裝的HttpResponseMessage對象進行的,在HttpResponseMessage中保存的響應內容就是客戶端接收到的內容。左圖基本揭示了Self Host寄宿模式下整個消息處理管道的結構。
實例演示:創建自定義HttpServer模擬HttpSelfHostServer的工作原理
通過上麵的介紹,我想讀者朋友們應該對Self Host模式下消息處理管道如何進行請求的監聽、接收、處理和響應已經有了全麵的了解。如果我們能夠創建一個自定義的HttpServer來模擬HttpSelfHostServer的工作原理,我想大家對此的印象一定更加深刻。在本章內容即將完結之前,我們就來完成這麼一個演示實例。
我們通過繼承HttpServer創建如下一個用於模擬HttpSelfHostServer的MyHttpSelfHostServer類型。兩者對於請求的監聽、接收和響應的實現原理是一致的,不同之處在於HttpSelfHostServer基本采用異步的操作方式,MyHttpSelfHostServer采用同步編程方式。
1: public class MyHttpSelfHostServer: HttpServer
2: {
3: public Uri BaseAddress { get; private set; }
4: public IChannelListener<IReplyChannel> ChannelListener { get; private set; }
5:
6: public MyHttpSelfHostServer(HttpConfiguration configuration, Uri baseAddress)
7: : base(configuration)
8: {
9: this.BaseAddress = baseAddress;
10: }
11:
12: public void Open()
13: {
14: HttpBinding binding = new HttpBinding();
15: this.ChannelListener = binding.BuildChannelListener<IReplyChannel>(this.BaseAddress);
16: this.ChannelListener.Open();
17:
18: IReplyChannel channnel = this.ChannelListener.AcceptChannel();
19: channnel.Open();
20:
21: while (true)
22: {
23: RequestContext requestContext = channnel.ReceiveRequest(TimeSpan.MaxValue);
24: Message message = requestContext.RequestMessage;
25: MethodInfo method = message.GetType().GetMethod("GetHttpRequestMessage");
26: HttpRequestMessage request = (HttpRequestMessage)method.Invoke(message, new object[] {true});
27: Task<HttpResponseMessage> processResponse = base.SendAsync(request, new CancellationTokenSource().Token);
28: processResponse.ContinueWith(task =>
29: {
30: string httpMessageTypeName = "System.Web.Http.SelfHost.Channels.HttpMessage, System.Web.Http.SelfHost";
31: Type httpMessageType = Type.GetType(httpMessageTypeName);
32: Message reply = (Message)Activator.CreateInstance(httpMessageType, new object[] { task.Result });
33: requestContext.Reply(reply);
34: });
35: }
36: }
37:
38: public void Close()
39: {
40: if (null != this.ChannelListener && this.ChannelListener.State == CommunicationState.Opened)
41: {
42: this.ChannelListener.Close();
43: }
44: }
45: }
MyHttpSelfHostServer的隻讀屬性BaseAddress表示監聽基地址,該屬性直接在構造函數中指定。與HttpSelfHostServer不同的是,用於創建MyHttpSelfHostServer提供的配置對象是一個HttpConfiguration對象而不再是HttpSelfHostConfiguration。
在Open方法中,我們根據提供的監聽基地址利用HttpBinding對象創建一個ChannelListener對象,MyHttpSelfHostServer的隻讀屬性ChannelListener引用的也正是這個對象。在開啟該ChannelListener之後,我們調用其AccpetChannel方法創建信道棧,最終返回位於棧頂的Channel。在該Channel開啟的情況下,我們在一個“永不終止”的While循環中調用其ReceiveRequest方法進行請求的監聽。
當信道棧成功接收請求消息後(這是一個HttpMessage對象),我們從中提取出被封裝的HttpRequestMessage對象,並將其作為參數調用SendAsync方法,表示請求的HttpReuqestMessage自此進入了消息處理管道這個流水車間。
調用SendAsync方法返回的是一個Task<HttpResponseMessage>對象,我們執行這個Task對象並獲得表示響應的HttpResponseMessage對象,然後以反射的形式將其封裝成HttpMessage對象。我們最終利用此HttpMessage對象對請求作最終的響應。HttpSelfHostServer定義了OpenAsync和CloseAsync方法開啟和關閉監聽器,與之相匹配,我們也為Open方法定義了匹配的Close方法來關閉已經開啟的ChannelListener。
為了驗證我們自定義的MyHttpSelfHostServer是否能夠替代“原生”的HttpSelfHostServer,我們在一個控製台中定義了如下一個繼承自ApiController的ContactsController。它具有兩個重載的Action方法Get,前者用於返回所有的聯係人列表,後者返回指定ID的某個聯係人信息。
1: public class ContactsController : ApiController
2: {
3: private static List<Contact> contacts = new List<Contact>
4: {
5: new Contact{ Id="001", Name = "張三", PhoneNo="123", EmailAddress="zhangsan@gmail.com"},
6: new Contact{ Id="002",Name = "李四", PhoneNo="456", EmailAddress="lisi@gmail.com"}
7: };
8:
9: public IEnumerable<Contact> Get()
10: {
11: return contacts;
12: }
13:
14: public Contact Get(string id)
15: {
16: return contacts.FirstOrDefault(c => c.Id == id);
17: }
18: }
19:
20: public class Contact
21: {
22: public string Id { get; set; }
23: public string Name { get; set; }
24: public string PhoneNo { get; set; }
25: public string EmailAddress { get; set; }
26: }
在作為入口的Main方法中我們編寫了如下一段簡單的“寄宿”程序。我們根據創建的HttpConfiguration對象和指定的監聽基地址(“https://127.0.0.1:3721”)創建了一個MyHttpSelfHostServer對象。在調用Open方法開始監聽之前,我們注冊了一個URL模板為“https://127.0.0.1:3721”的HttpRoute。
1: class Program
2: {
3: static void Main(string[] args)
4: {
5: using (MyHttpSelfHostServer httpServer = new MyHttpSelfHostServer(new HttpConfiguration(), new Uri("https://127.0.0.1:3721")))
6: {
7: httpServer.Configuration.Routes.MapHttpRoute(
8: name : "DefaultApi",
9: routeTemplate : "api/{controller}/{id}",
10: defaults : new { id = RouteParameter.Optional });
11:
12: httpServer.Open();
13: Console.Read();
14: }
15: }
16: }
運行該程序之後,這個“宿主”程序便開始進行請求的監聽。現在我們直接利用瀏覽器對定義在ContactsController中的兩個Action方法Get發起請求,通過注冊的HttpRoute和“請求的HTTP方法直接作為Action名稱”的原理,我們使用的URL分別為“https://127.0.0.1:3721/api/contacts”和“https://127.0.0.1:3721/api/contacts/001”。如右圖所示,我們期望的聯係人信息直接以XML的形式顯示在瀏覽器中,由此可見我們自定義的MyHttpSelfHostServer“不辱使命”。
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-25 15:04:12