<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [WCF REST] UriTemplate、UriTemplateTable與WebHttpDispatchOperationSelector

      REST服務采用面向資源的架構,而資源通過URI進行標識和定位,所以URI在REST中具有重要的地位。對于WCF來說,服務調用請求的URI映射為某個具體的操作,所以服務端需要解決的是如何根據請求URI選擇出對應的操作。如果采用SOAP,操作的選擇是根據消息的<Action>報頭來實現的,那么REST服務又采用怎樣的操作選擇機制呢?

      目錄
      一、URI模板
      二、UriTemplate
      三、UriTemplateTable
      四、WebHttpDispatchOperationSelector
      五、實例演示、自定義OperationSelector實現基于URI模板的操作選擇機制

      一、URI模板

      在定義服務契約的時候,我們可以通過應用在操作方法上的WebGetAttribute和WebInvokeAttribute特性的UriTemplate屬性定義一個URI模板。如下面的代碼片斷所示,我們為契約接口ICalculator的Add操作定義了Uri模板"Add/{x}/{y}"),路經部分{x}和{y}對應著操作方法同名的參數。如果終結點地址為http://127.0.0.1:3721/calculatorservice,我們可以訪問地址http://127.0.0.1:3721/calculatorservice/add/1/2調用Add操作并傳入操作數1和2。

         1: [ServiceContract(Namespace = "http://www.artech.com/")]
         2: public interface ICalculator
         3: {
         4:     [WebGet(UriTemplate = "Add/{x}/{y}")]
         5:     double Add(double x, double y);
         6: }

      關于URI模板定義的語法和規范,請參考http://msdn.microsoft.com/en-us/library/bb675245.aspx

      二、UriTemplate

      在Web HTTP編程模型中,URI模板通過具有如下定義的UriTemplate表示。UriTemplate具有一系列的構造函數重載,這些重載除了接受以字符串類表示的URI模板作為參數之外,還具有額外的一些參數。布爾類型的參數ignoreTrailingSlash表示是否需要忽略URI模板最右邊的斜杠(“/”),而字典參數additionalDefaults用于指定默認變量值。

         1: public class UriTemplate
         2: {
         3:     //其他成員
         4:     public UriTemplate(string template);
         5:     public UriTemplate(string template, bool ignoreTrailingSlash);
         6:     public UriTemplate(string template, IDictionary<string, string> additionalDefaults);
         7:     public UriTemplate(string template, bool ignoreTrailingSlash, IDictionary<string, string> additionalDefaults); 
         8:  
         9:     public IDictionary<string, string> Defaults { get; }
        10:     public bool IgnoreTrailingSlash { get; }
        11:     public ReadOnlyCollection<string> PathSegmentVariableNames { get; }
        12:     public ReadOnlyCollection<string> QueryValueVariableNames { get; }
        13:  
        14:     public Uri BindByName(Uri baseAddress, IDictionary<string, string> parameters);
        15:     public Uri BindByName(Uri baseAddress, NameValueCollection parameters);
        16:     public Uri BindByName(Uri baseAddress, IDictionary<string, string> parameters, bool omitDefaults);
        17:     public Uri BindByName(Uri baseAddress, NameValueCollection parameters, bool omitDefaults);
        18:     public Uri BindByPosition(Uri baseAddress, params string[] values);
        19:  
        20:     public UriTemplateMatch Match(Uri baseAddress, Uri candidate);
        21: }

      UriTemplate具有三個只讀的屬性。IgnoreTrailingSlash屬性返回調用構造函數指定的同名參數,默認值為True,意味著在默認情況在模板字符串結尾指定的斜杠會被忽略。PathSegmentVariableNames和QueryValueVariableNames則返回路徑表達式和查詢字符串表達式中指定的變量名。

      我們可以指定基地址和變量值調用BindByName方法得到一個完整的URI。變量值可以通過字典和NameValueCollection對象的形式指定,其中的Key和Value分別表示變量名和變量值。在BindByPosition方法中我們以字符串數組的形式指定變量值,URI模板中的變量會按照出現的先后順利進行替換并最終得到一個完整的URI。

      方法Match用于判斷URI模板是否與指定的某個完整的URI匹配,被用于進行匹配比較的URI通過參數candidate表示,而第一個參數代表的是基地址。如果不匹配則返回Null,否則返回具有如下定義的UriTemplateMatch對象。

         1: public class UriTemplateMatch
         2: {
         3:     public Uri RequestUri { get; set; }
         4:     public Uri BaseUri { get; set; }
         5:     public UriTemplate Template { get; set; }
         6:  
         7:     public NameValueCollection BoundVariables { get; }
         8:     public NameValueCollection QueryParameters { get; }
         9:  
        10:     public Collection<string> RelativePathSegments { get; }
        11:     public Collection<string> WildcardPathSegments { get; }
        12:  
        13:     public object Data { get; set; }
        14: }

      UriTemplateMatch屬性Template返回的是調用Match方法的UriTemplate對象,而基地址和被用于進行匹配判斷的Uri分別通過BaseUri和RequestUri屬性返回。被綁定變量(變量名稱和值)以及查詢字符串參數(參數名稱和值)分別通過NameValueCollection類型的屬性BoundVariables和QueryParameters返回。屬性RelativePathSegments返和WildcardPathSegments分別返回相對路徑段和通配路徑段。通過可讀寫屬性Data,我們可以將任意一個對象附加在UriTemplateMatch上面。

      三、UriTemplateTable

      具有如下定義UriTemplateTable本質上是一個KeyValuePair<UriTemplate, object>對象集合,我們可以使用任意類型的對象和某個UriTemplate對象關聯。當我們指定某個Uri對象調用它的Match方法時,會遍歷集合中的所有UriTemplate對象并調用它的Match方法,最終返回一個UriTemplateMatch集合。對于每個UriTemplateMatch對象,其Data屬性直接上就是與對應UriTemplate關聯的對象。

      而MatchSingle方法被執行的時候會在內部調用Match方法,如果沒有匹配的UriTemplate,返回Null;如果只有唯一匹配的UriTemplate,則返回對應的UriTemplateMatch對象;如果多個UriTemplate同時匹配指定的Uri,直接拋出異常。

         1: public class UriTemplateTable
         2: {   
         3:     public UriTemplateTable();
         4:     public UriTemplateTable(IEnumerable<KeyValuePair<UriTemplate, object>> keyValuePairs);
         5:     public UriTemplateTable(Uri baseAddress);
         6:     public UriTemplateTable(Uri baseAddress, IEnumerable<KeyValuePair<UriTemplate, object>> keyValuePairs);
         7:  
         8:     public void MakeReadOnly(bool allowDuplicateEquivalentUriTemplates);
         9:     public Collection<UriTemplateMatch> Match(Uri uri);
        10:     public UriTemplateMatch MatchSingle(Uri uri);
        11:  
        12:     public Uri BaseAddress { get; set; }
        13:     public Uri OriginalBaseAddress { get; }
        14:     public bool IsReadOnly { get; }
        15:     public IList<KeyValuePair<UriTemplate, object>> KeyValuePairs { get; }
        16: }

      構成UriTemplateTable的KeyValuePair<UriTemplate, object>集合通過只讀屬性KeyValuePairs返回,該屬性在構造函數中被初始化。屬性BaseAddress 表示基地址,可以在構造函數中初始化,也可以直接通過屬性賦值的方式指定。只讀屬性OriginalBaseAddress表示在構造函數或者針對BaseAddress的屬性賦值中指定的Uri,它和BaseAddress唯一不同之處在于:后者經過“標準化(Normalization)”。

         1: Uri baseAddress = new Uri("http://127.0.0.1:3721/calculatorservice");
         2: UriTemplateTable uriTemplateTable = new UriTemplateTable(baseAddress);
         3: Console.WriteLine("{0,-20}: {1}", "BaseAddress", uriTemplateTable.BaseAddress);
         4: Console.WriteLine("{0,-20}: {1}", "OriginalBaseAddress", uriTemplateTable.OriginalBaseAddress);

      在如上所示的代碼片斷中,我們針對基地址http://127.0.0.1:3721/calculatorservice創建了一個UriTemplateTable對象,然后分別在控制臺中打印出它的BaseAddress和OriginalBaseAddress屬性表示的Uri。從如下所示的輸出結果可以看出,OriginalBaseAddress正是我們指定的原生基地址,而經過標準化處理后的BaseAddress的路徑部分全部大寫,并且添加了后綴“/”。

         1: BaseAddress         : http://localhost/CALCULATORSERVICE/
         2: OriginalBaseAddress : http://127.0.0.1:3721/calculatorservice

      UriTemplateTable的只讀屬性IsReadOnly表示是否處于只讀狀態,我們通過調用MakeReadOnly方法將此屬性設置為True。一旦調用了該方法,我們便不允許對該UriTemplateTable作任何改變。MakeReadOnly具有一個布爾類型的參數allowDuplicateEquivalentUriTemplates表示是否允許存在多個結構等效的UriTemplate。如果該參數為False,多個結構等效UriTemplate的存在會導致異常的發生。

      四、WebHttpDispatchOperationSelector

      我們所說的服務調用實際上是針對寄宿服務的某個終結點的某個操作的調用,服務端運行時最終需要根據服務調用請求選擇出正確的操作。對于針對SOAP的服務調用來說,我們一般通過其<Action>報頭作為操作選擇的依據,而對于REST服務來說,請求的地址決定了對應的操作。

      WCF服務端運行時通過DispatchOperationSelector根據請求消息進行操作的選擇,而Web HTTP編程模型通過自定義的DispatchOperationSelector實現了最終的操作選擇,這就是我們接下來需要著重介紹的WebHttpDispatchOperationSelector類型。

      WebHttpDispatchOperationSelector針對請求地址的操作選擇機制是通過UriTemplateTable實現的。我們通過ServiceEndpoint對象創建WebHttpDispatchOperationSelector的時候,會遍歷終結點契約的所有操作并獲得通過WebGetAttribute/WebInvokeAttribute特性設置URI模板。然后根據URI模板創建UriTemplate對象并最終創建UriTemplateTable。在真正需要進行操作選擇的時候,只需要調用該UriTemplateTable的MatchSingle方法并傳入請求地址,如果匹配則表明UriTemplate對應的操作就是我們需要選擇的操作。

      五、實例演示、自定義OperationSelector實現基于URI模板的操作選擇機制

      為了讓讀者對WebHttpDispatchOperationSelector的操作選擇策略有一個深刻的例子,我按照大致的原理自定義一個DispatchOperationSelector,我們將其命名為WebHttpOperationSelector。整個WebHttpOperationSelector的定義如下所示。

         1: public class WebHttpOperationSelector:IDispatchOperationSelector
         2: {
         3:     public IDictionary<string, UriTemplateTable> UriTemplateTables { get; private set; }    
         4:     public WebHttpOperationSelector(ServiceEndpoint endpoint)
         5:     {
         6:         this.UriTemplateTables = new Dictionary<string, UriTemplateTable>();
         7:         Uri baseAddress = endpoint.Address.Uri;
         8:         foreach (var operation in endpoint.Contract.Operations)
         9:         {
        10:             WebGetAttribute webGet = operation.Behaviors.Find<WebGetAttribute>();
        11:             WebInvokeAttribute webInvoke = operation.Behaviors.Find<WebInvokeAttribute>();
        12:             string method = (null != webGet) ? "GET" : webInvoke.Method;
        13:             UriTemplateTable uriTemplateTable;
        14:             if (!this.UriTemplateTables.TryGetValue(method, out uriTemplateTable))
        15:             {
        16:                 uriTemplateTable = new UriTemplateTable(baseAddress);
        17:                 this.UriTemplateTables.Add(method, uriTemplateTable);
        18:             }
        19:             string template = (null != 
        20:             webGet)?webGet.UriTemplate:webInvoke.UriTemplate;
        21:             uriTemplateTable.KeyValuePairs.Add(new KeyValuePair<UriTemplate, object>(new UriTemplate(template),operation.Name));
        22:         }
        23:     }
        24:  
        25:     public string SelectOperation(ref Message message)
        26:     {
        27:         if (!message.Properties.ContainsKey(HttpRequestMessageProperty.Name))
        28:         {
        29:             return "";
        30:         }
        31:         HttpRequestMessageProperty messageProperty = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];
        32:  
        33:         var address = message.Headers.To;
        34:         var method = messageProperty.Method;
        35:         UriTemplateTable uriTemplateTable = null;
        36:         if(!this.UriTemplateTables.TryGetValue(method, out uriTemplateTable))
        37:         {
        38:             return "";
        39:         }
        40:  
        41:         UriTemplateMatch match = uriTemplateTable.MatchSingle(address);
        42:         if(null == match)
        43:         {
        44:             return "";
        45:         }
        46:         return match.Data.ToString();
        47:     }
        48: }

      WebHttpOperationSelector具有一個字典類型的屬性UriTemplateTables,Key和Value分別代表請求消息的HTTP方法和與之對應的UriTemplateTable對象。我們基于一個ServiceEndpoint對象來創建WebHttpOperationSelector,在構造函數中我們對UriTemplateTables屬性進行了初始化。從上面的代碼片斷我們可以看出UriTemplateTable中基于某個操作的UriTemplate對象與操作名稱關聯。

      在真正實施操作選擇的SelectOperation方法中,我們根據請求消息的HTTP方法從UriTemplateTables屬性中得到對應的UriTemplateTable對象。然后以請求消息的<To>報頭表示的Uri為參數調用UriTemplateTable的MatchSingle方法,如果該方法返回一個具體的UriTemplateMatch對象,其Data屬性即為對應操作的名稱。

      為了驗證WebHttpOperationSelector能夠正確地根據請求消息的目標地址選擇出對應的操作,我們通過一個簡單的實例來驗證。如下面的代碼片斷所示,我們為熟悉的計算服務定義了如下一個契約接口ICalculator。表示加、減、乘、除運算的四個方法應用了WebGetAttribute特性并定義相應的URI模板。

         1: [ServiceContract(Namespace = "http://www.artech.com")]
         2: public interface ICalculator
         3: {
         4:     [WebGet(UriTemplate = "Add/{x}/{y}")]
         5:     double Add(double x, double y);
         6:  
         7:     [WebGet(UriTemplate = "Substract/{x}/{y}")]
         8:     double Substract(double x, double y);
         9:  
        10:     [WebGet(UriTemplate = "Multiply/{x}/{y}")]
        11:     double Multiply(double x, double y);
        12:  
        13:     [WebGet(UriTemplate = "Divide/{x}/{y}")]
        14:     double Divide(double x, double y);
        15: }

      然后我們定義如下一個靜態方法GetOperationName借助于DispatchOperationSelector對象根據表示請求地址的address選擇出正確的操作名稱。在這個方法中,我們創建了一個空的消息并將傳入的URI作為該消息的To報頭,并通過添加一個HttpRequestMessageProperty類型的消息屬性將HTTP方法設置為GET。最終將創建的消息作為參數調用DispatchOperationSelector的SelectOperation方法得到正確的操作名稱。

         1: static string  GetOperationName(Uri address, 
         2:     IDispatchOperationSelector operationSelector)
         3: {
         4:     Message message = Message.CreateMessage(MessageVersion.None, "");
         5:     message.Headers.To = address;
         6:     HttpRequestMessageProperty messageProperty = new HttpRequestMessageProperty();
         7:     messageProperty.Method = "GET";
         8:     message.Properties.Add(HttpRequestMessageProperty.Name, messageProperty);
         9:     return operationSelector.SelectOperation(ref message);
        10: }

      在如下的代碼片斷中,我們針對契約接口ICalculator類型創建了一個ServiceEndpoint對象,其地址為http://127.0.0.1:3721/calculatorservice,綁定類型為WebHttpBinding。然后基于該ServiceEndpoint創建我們定義WebHttpOperationSelector對象。最后我們創建了四個分別表示針對計算服務運算操作的Uri并調用GetOperationName方法測試是否能夠根據我們自定義的WebHttpOperationSelector對象正確選擇出相應的操作。

         1: EndpointAddress address = new EndpointAddress("http://127.0.0.1:3721/calculatorservice");
         2: Binding binding = new WebHttpBinding();
         3: ContractDescription contract = ContractDescription.GetContract(typeof(ICalculator));
         4: ServiceEndpoint endpoint = new ServiceEndpoint(contract, binding, address);
         5: WebHttpOperationSelector operationSelector = new WebHttpOperationSelector(endpoint);
         6:  
         7: Uri addAdress       =  new Uri("http://127.0.0.1:3721/calculatorservice/add/1/2");
         8: Uri substractAdress =  new Uri("http://127.0.0.1:3721/calculatorservice/substract/1/2");
         9: Uri multiplyAdress  =  new Uri("http://127.0.0.1:3721/calculatorservice/multiply/1/2");
        10: Uri divideAdress    =  new Uri("http://127.0.0.1:3721/calculatorservice/divide/1/2");
        11:  
        12: Console.WriteLine(GetOperationName(addAdress,operationSelector));
        13: Console.WriteLine(GetOperationName(substractAdress, operationSelector));
        14: Console.WriteLine(GetOperationName(multiplyAdress, operationSelector));
        15: Console.WriteLine(GetOperationName(divideAdress, operationSelector));

      上面的程序執行之后在控制臺上會輸出如下所示的結果,它們正是與指定URI匹配的操作名稱。

         1: Add
         2: Substract
         3: Multiply
         4: Divide

      除了為幫助頁面提供操作選擇和對默認URI模板(應用在操作方法上的WebGetAttribute和WebInvokeAttribute特性并沒有對UriTemplate屬性進行顯式設置)的支持外,WebHttpDispatchOperationSelector實現操作選擇的核心邏輯與我們自定義的WebHttpOperationSelector基本類似。WebHttpDispatchOperationSelector最終通過終結點行為WebHttpBehavior(ApplyDispatchBehavior方法)應用到分發運行時上。

      posted @ 2012-02-09 09:13  Artech  閱讀(11753)  評論(14)    收藏  舉報
      主站蜘蛛池模板: 精品国产一区二区三区大| 99视频偷窥在线精品国自产拍| 国产精品剧情亚洲二区| 五月天天天综合精品无码| 麻豆一区二区中文字幕| 国产无遮挡免费真人视频在线观看| 午夜A理论片在线播放| 桂阳县| 精精国产xxxx视频在线 | 久久99日韩国产精品久久99| 亚洲最大的成人网站| 亚洲av片在线免费观看| 国产一级片内射在线视频| 日本边添边摸边做边爱喷水| 99在线视频免费观看| 国产日韩精品欧美一区灰| 国产精品 欧美激情 在线播放| 粉嫩国产av一区二区三区| 久久综合给合久久狠狠97色 | 国产色无码精品视频免费| 泰安市| 久久这里只精品国产2| 亚洲精品一区二区三区在| A毛片终身免费观看网站| 亚洲成在人线在线播放无码 | 天干天干夜啦天干天干国产| 亚洲情综合五月天| 欧美亚洲一区二区三区在线| 亚洲一区二区三区啪啪| 亚洲精品蜜桃久久久久久| 久久不见久久见中文字幕免费| 国产盗摄xxxx视频xxxx| 国产福利社区一区二区| 久久精品夜色国产亚洲av| 日韩av日韩av在线| 国产成人无码免费网站| 女同亚洲精品一区二区三| 国产精品亚洲av三区色| av老司机亚洲精品天堂| 万盛区| 国产一区二区三区黄色片|