2015-10-08 45 views
1

好吧,我已經搜索了一堆問題的答案,我似乎只能從2011年開始爲.NET 3.5找到文章和文檔。 ..所以我希望能夠在.NET 4.5(及更高版本)中找到有關WCF的更新信息。如何在WCF的uri路徑中使用WebHttpBinding中的強類型參數

我有一個綁定到webHttpBinding的WCF服務。它使用的是通過該項目的身份與一個開放的模板,例如檢索一個URI模板:

[WebInvoke(Method="GET", UriTemplate = "/{identity}")] 
public ResponseItem Get(string identity) 
{ 
    //Convert identity to a Guid which is the correct type for the identity 
    //Retrieve object 
} 

我真正想要做的是刪除值轉換爲GUID和移動它到堆棧清理代碼,並具有:

[WebInvoke(Method="GET", UriTemplate = "/{identity}")] 
public ResponseItem Get(Guid identity) 
{ 
    //Retrieve object 
} 

我實現與其他類型的結合這使用自定義的行爲和QueryStringConverter是可能。我也意識到webHttpBinding默認字符串的原因是,在地址中傳遞的固有值應該是在語義上是字符串 - 因爲地址是基於字符串的。所以也許我所問的可能沒有意義。

在我的應用程序的上下文中,字符串在語義上是不正確的,它讓我感到惱火,因爲這個類混淆了轉換代碼,它不應該成爲類的關注點,但改變綁定不是一個選項,因爲現有的客戶端正在使用它。

是否有在WCF管道對WCF(例如IParameterInspector,IServiceBehavior接口),其中該值的轉換既可以適當,使得由時間被調用的方法,該參數的當前版本的可擴展性點可以是正確的類型?

回答

4

更新回答 -

看着您的評論後,我得到了點。所以你想提供字符串,然後在OperationInovker進入圖片之前進行投射。所以我骯髒的玩弄了我的手,最後做到了。

這是我所做的。一個新的類從WebHttpBehavior派生,這將給我們一個地方,我們可以擴展或覆蓋WebHttpBidning的現有行爲。

public class MyWebHttpBehavior : WebHttpBehavior 
{ 
} 

雖然這是一個破解和但這會工作。鍵入參數的問題是,URL模板格式化程序通過檢查string類型的方法簽名來拋出異常,所以我通過使用方法GetRequestDispatchFormatter來控制BindingInformation而擺脫了這種情況。

protected override IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint) 
    { 
     foreach (var item in operationDescription.Messages[0].Body.Parts) 
     { 
      item.Type = typeof(string); 
     } 

     return base.GetRequestDispatchFormatter(operationDescription, endpoint); 
    } 

應用此行爲後,運行時將不再爲String參數檢查拋出異常。現在我需要改變OperationInvoker,因爲如果你運行這個,那麼當你從客戶端調用Invalid cast的操作時,這會引起不必要的反應。

現在來看圖片中的IOperationInvoker。我只是將類型對象的input []中的值從String轉換爲Guid,並將其傳遞給Invoker。

public class ValueCastInvoker : IOperationInvoker 
{ 
    readonly IOperationInvoker _invoker; 

    public ValueCastInvoker(IOperationInvoker invoker) 
    { 
     _invoker = invoker; 
    } 

    public ValueCastInvoker(IOperationInvoker invoker, Type type, Object value) 
    { 
     _invoker = invoker; 
    } 

    public object[] AllocateInputs() 
    { 
     return _invoker.AllocateInputs().ToArray(); 
    } 

    private object[] CastCorrections(object[] inputs) 
    { 
     Guid obj; 

     var value = inputs[0] as string; 

     if (Guid.TryParse(value, out obj)) 
     { 
      return new[] { (object)obj }.Concat(inputs.Skip(1)).ToArray(); 
     } 

     return inputs.ToArray(); 
    } 

    public object Invoke(object instance, object[] inputs, out object[] outputs) 
    { 
     return _invoker.Invoke(instance, CastCorrections(inputs), out outputs); 
    } 

    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) 
    { 
     return _invoker.InvokeBegin(instance, inputs, callback, state); 
    } 

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) 
    { 
     return _invoker.InvokeEnd(instance, out outputs, result); 
    } 

    public bool IsSynchronous 
    { 
     get { return _invoker.IsSynchronous; } 
    } 
} 

現在,在這裏,我花了很長時間才弄清楚是如何注入這個自定義操作inovker管道。我發現了一個相關的stackoverflow答案here。並按照人們建議的方式實施。

在此處添加摘要:必須實施新的IOperationBehavior並將其與DispatcherRuntime附加在一起。

public class MyOperationBehavior : IOperationBehavior 
{ 
    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
    { 
    } 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
    { 
     dispatchOperation.Invoker = new ValueCastInvoker(dispatchOperation.Invoker); 
    } 

    public void Validate(OperationDescription operationDescription) 
    { 
    } 
} 

現在MyWebHttpBehavior覆蓋ApplyDispatchBehavior和介紹上述實施IOperationBehavior

public override void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { 
     foreach (var operation in endpoint.Contract.Operations) 
     { 
      if (operation.Behaviors.Contains(typeof(MyOperationBehavior))) 
       continue; 

      operation.Behaviors.Add(new MyOperationBehavior()); 
     } 

     base.ApplyDispatchBehavior(endpoint, endpointDispatcher); 
    } 

現在所有這些黑客和擴展將使這個法律。

[WebInvoke(Method = "GET", UriTemplate = "/{id}")] 
    string GetValue(Guid id); 

免責聲明:我很開心這個實驗和exntesion應用自定義行爲,但我沒有帶檢查受災地區。因此,請使用它自己的風險,並儘可能隨意更改/增強。 對不起,對錯字

更新2

我創建了一個庫來包裝這個網頁的HTTP行爲擴展。該庫爲方法參數(多個)中的其他值類型提供更多支持。 Check this out

+0

在值被取出URI並傳入方法,你會認爲你可以轉換它...也許在MethodInvoker? – BenAlabaster

+0

@BenAlabaster我已經更新了答案,是的,雖然MethodInvoker工作,但必須應用幾個黑客。希望你喜歡它並在這裏添加更多有價值的內容。 – vendettamit

+0

...這裏是完整的代碼https://gist.github.com/vendettamit/a40f619c9dfcc3026635#file-webhttpbehaviorextension-cs – vendettamit

0

您需要提供QueryStringConverter的自定義實現。這是您需要的代碼。只需將GuidConverterWebHttpBehavior作爲服務行爲添加,並且所有內容都應該可以正常工作。

class GuidQueryStringConverter : QueryStringConverter 
{ 
    public override bool CanConvert(Type type) 
    { 
     return type == typeof(Guid) || base.CanConvert(type); 
    } 

    public override object ConvertStringToValue(string parameter, Type parameterType) 
    { 
     if (parameterType == typeof(Guid)) 
     { 
      Guid guid; 
      if(Guid.TryParse(parameter, out guid)) 
      { 
       return guid; 
      } 
     } 

     return base.ConvertStringToValue(parameter, parameterType); 
    } 
} 

public class GuidConverterWebHttpBehavior : WebHttpBehavior 
{ 
    protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription) 
    { 
     return new GuidQueryStringConverter(); 
    } 
} 
+0

這工作像一個魅力與其他類型的綁定,但與WebHttpBinding和UriTemplates你在哪裏引用路徑段而不是查詢字符串,這個用例引發了一個異常。 – BenAlabaster

相關問題