日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

聚焦WCF行为的扩展

發布時間:2025/5/22 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 聚焦WCF行为的扩展 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

WCF以其靈活的可擴展架構為開發者提供了方便,其中對行為的擴展或許是應用中最為常見的。自 定義對行為的擴展并不復雜,但仍有許多細節需要注意。在服務端,一般是對DispatchRuntime和DispatchOperation進行擴展, 擴展點包括了對參數和消息的檢查,以及操作調用程序,它們對應的接口分別為 IParameterInspector,IDispatchMessageInspector以及IOperationInvoker。而在客戶端,則是對ClientRuntime和ClientOperation進行擴展,擴展點包括對參數和消息的檢查,對應的接口分別為 IParameterInspector和IClientMessageInspector。這些接口類型均被定義在 System.ServiceModel.Dispatcher命名空間下,其中IParameterInspector接口可以同時作用在服務端和客戶 端。

對這些接口的實現,有點類似于AOP的實現,可以對方法調用前和調用后注入一些額外的邏輯,所以通常會將這些擴展稱為偵聽器。例如IParameterInspector接口,就定義了如下方法:

void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState);??????
object BeforeCall(string operationName, object[] inputs);

在調用服務對象的目標方法前,會調用BeforeCall方法,而在調用后則會調用AfterCall方法。例如我們可在方法調用前檢驗計算方法的參數是否小于0,如果小于0則拋出異常:

public class CalculatorParameterInspector:IParameterInspector
{
??? public void BeforeCall(string operationName, object[] inputs)
??? {
??????? int x = inputs[0] as int;
??????? int y = inputs[1] as int;
??????? if (x <0 || y < 0)
??????? {
?????????? throw new FaultException("The number can not be less than zero.");
??????? }
??????? return null;
??? }

??? public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
??? {
??????? //empty;
??? }
}

對消息的檢查區分了服務端和客戶端,接口方法根據消息傳遞的順序剛好相反[注]。我們可以通過接口方法對消息進行處理,例如打印消息的Header:

public class PrintMessageInterceptor : IDispatchMessageInspector
{
??? #region IDispatchMessageInspector Members

??? public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
??? {
??????? MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
??????? request = buffer.CreateMessage();

??????? Console.WriteLine("After Receive Request:");
??????? foreach (MessageHeader header in request.Headers)
??????? {
??????????? Console.WriteLine(header);
??????? }
??????? Console.WriteLine(new string('*', 20));
??????? return null;
??? }

??? public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
??? {
??????? MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
??????? reply = buffer.CreateMessage();

??????? Console.WriteLine("Before Send Request:");
??????? foreach (MessageHeader header in reply.Headers)
??????? {
??????????? Console.WriteLine(header);
??????? }
??????? Console.WriteLine(new string('*', 20));
??? }

??? #endregion
}

WCF提供了四種類型的行為:服務行為、終結點行為、契約行為和操作行為。 這四種行為分別定義了四個接口:IServiceBehavior,IEndpointBehavior,IContractBehavior以及 IOperationBehavior。雖然是四個不同的接口,但它們的接口方法卻基本相同,分別為 AddBindingParameters(),ApplyClientBehavior()以及ApplyDispatchBehavior()。注 意,IServiceBehavior由于只能作用在服務端,因此并不包含ApplyClientBehavior()方法

我們可以定義自己的類實現這些接口,但需要注意幾點:
1、行為的作用范圍,可以用如下表格表示:

作用域

接口

影響范圍

服務

終結點

契約

操作

服務

IServiceBehavior

Y

Y

Y

Y

終結點

IEndpointBehavior

?

Y

Y

Y

契約

IContractBehavior

?

?

Y

Y

操作

IOperationBehavior

?

?

?

Y

2、可以利用自定義特性的方式添加擴展的服務行為、契約行為和操作行為,但不能添加終結點行為;可以利用配置文件添加擴展服務行為和終結點行為,但不能添加契約行為和操作行為。但這些擴展的行為都可以通過ServiceDescription添加

利用特性添加行為,意味著我們在定義自己的擴展行為時,可以將其派生自Attribute類,然后以特性方式添加。例如:

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface)]
public class MyServiceBehavior:Attribute, IServiceBehavior...

[MyServiceBehavior]
public interface IService...

如果以配置文件的方式添加行為,則必須定義一個類繼承自BehaviorExtensionElement(屬 于命名空間System.ServiceModel.Configuration),然后重寫屬性BehaviorType以及 CreateBehavior()方法。BehaviorType屬性返回的是擴展行為的類型,而CreateBehavior()方法則負責創建該擴展行為的對象實例:

public class MyBehaviorExtensionElement:BehaviorExtensionElement
{
??? public MyBehaviorExtensionElement() { }
??? public override Type BehaviorType
??? {
??????? get { return typeof(MyServiceBehavior); }
??? }

??? protected override object CreateBehavior()
??? {
??????? return new MyServiceBehavior();
??? }
}

如果配置的Element添加了新的屬性,則需要為新增的屬性應用ConfigurationPropertyAttribute,例如:

[ConfigurationProperty("providerName",IsRequired = true)]
public virtual string ProviderName
{
??? get
??? {
??????? return this["ProviderName"] as string;
??? }
??? set
??? {
??????? this["ProviderName"] = value;
??? }
}

配置文件中的配置方法如下所示:

<configuration>
? <system.serviceModel>??
??? <services>
????? <service name="MessageInspectorDemo.Calculator">
??????? <endpoint behaviorConfiguration="messageInspectorBehavior"
????????????????? address="http://localhost:801/Calculator"?????????????????
????????????????? binding="basicHttpBinding"
????????????????? contract="MessageInspectorDemo.ICalculator"/>
????? </service>
??? </services>
??? <behaviors>
????? <serviceBehaviors>
??????? <behavior name="messageInspectorBehavior">
????????? <myBehaviorExtensionElement providerName="Test"/>
??????? </behavior>
????? </serviceBehaviors>
??? </behaviors>
??? <extensions>
????? <behaviorExtensions>
??????? <add name="myBehaviorExtensionElement"
???????????? type="MessageInspectorDemo.MyBehaviorExtensionElement, MessageInspectorDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
????? </behaviorExtensions>
??? </extensions>
? </system.serviceModel>
</configuration>

注 意,在<serviceBehaviors>一節中,<behavior>下 的<myBehaviorExtensionElement>就是我們擴展的行為,providerName則是 MyBehaviorExtensionElement增加的屬性。如果擴展了IEndpointBehavior,則配置節的名稱 為<endpointBehaviors>。<extensions>節負責添加自定義行為的擴展。其 中,<add>中的name值與<behavior>下 的<myBehaviorExtensionElement>對應。

特別注意的是<extensions>下的 type值,必須是類型的full name。第一個逗點前的內容為完整的類型名(包括命名空間),第二部分為完整的命名空間。Version,Culture以及 PublicKeyToken也是缺一不可的。每個逗點后必須保留一個空格,否則無法正確添加擴展行為的配置。這與反射有關,但太容易讓人忽略這一小細節。希望微軟能在后來的版本中修訂這個瑕疵。

3、在行為擴展的適當方法中,需要添加參數檢查、消息檢查或操作調用程序的擴展。這之間存在一定的對應關系。對于參數檢查,我們需要在IOperationBehavior接口類型中的ApplyClientBehavior()以及ApplyDispatchBehavior()中添加。例如對于之前的CalculatorParameterInspector,我們可以定義一個類CalculatorParameterValidation:

public class CalculatorParameterValidation:Attribute, IOperationBehavior
{
??????? #region IOperationBehavior Members
??????? public void AddBindingParameters(OperationDescription operationDescription,
??????????? BindingParameterCollection bindingParameters)
??????? {
??????? }

??????? public void ApplyClientBehavior(OperationDescription operationDescription,
??????????? ClientOperation clientOperation)
??????? {
??????????? CalculatorParameterInspector inspector = new CalculatorParameterInspector();
??????????? clientOperation.ParameterInspectors.Add(inspector);
??????? }

??????? public void ApplyDispatchBehavior(OperationDescription operationDescription,
??????????? DispatchOperation dispatchOperation)
??????? {
??????????? CalculatorParameterInspector inspector = new CalculatorParameterInspector();
??????????? dispatchOperation.ParameterInspectors.Add(inspector);
??????? }

??????? public void Validate(OperationDescription operationDescription)
??????? {
??????? }
??????? #endregion
}

如果檢查器與擴展行為在職責上沒有分離的必要,一個更好的方法是定義一個類同時實現IParameterInspector和IOperationBehavior接口,例如:

public class CalculatorParameterValidation:Attribute, IParameterInspector, IOperationBehavior
{
??????? #region IParameterInspector Members
??????? public void BeforeCall(string operationName, object[] inputs)
??????? {
??????????? int x = inputs[0] as int;
??????????? int y = inputs[1] as int;
??????????? if (x <0 || y < 0)
??????????? {
?????????????? throw new FaultException("The number can not be less than zero.");
??????????? }
??????????? return null;
??????? }

??????? public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
??????? {
??????????? //empty;
??????? }
??????? #endregion


??????? #region IOperationBehavior Members
??????? public void AddBindingParameters(OperationDescription operationDescription,
??????????? BindingParameterCollection bindingParameters)
??????? {
??????? }

??????? public void ApplyClientBehavior(OperationDescription operationDescription,
??????????? ClientOperation clientOperation)
??????? {
??????????? CalculatorParameterInspector inspector = new CalculatorParameterInspector();
??????????? clientOperation.ParameterInspectors.Add(this);
??????? }

??????? public void ApplyDispatchBehavior(OperationDescription operationDescription,
??????????? DispatchOperation dispatchOperation)
??????? {
??????????? CalculatorParameterInspector inspector = new CalculatorParameterInspector();
??????????? dispatchOperation.ParameterInspectors.Add(this);
??????? }

??????? public void Validate(OperationDescription operationDescription)
??????? {
??????? }
??????? #endregion
} 操作調用程序雖然通過IOperationBehavior進行關聯,但確是通過DispatchOperation的Invoker屬性。假定我們已經定義了一個實現IOperationInvoker的類MyOperationInvoker,則關聯的方法為:
public class MyOperationInvokerBehavior : Attribute, IOperationBehavior
{
??? #region IOperationBehavior Members
??? public void AddBindingParameters(OperationDescription operationDescription,
??????? BindingParameterCollection bindingParameters)
??? {
??? }
??? public void ApplyClientBehavior(OperationDescription operationDescription,
??????? ClientOperation clientOperation)
??? {??????????
??? }
??? public void ApplyDispatchBehavior(OperationDescription operationDescription,
??????? DispatchOperation dispatchOperation)
??? {
??????? dispatchOperation.Invoker = new MyOperationInvoker(dispatchOperation.Invoker);
??? }
??? public void Validate(OperationDescription operationDescription)
??? {
??? }
??? #endregion
}

?

至 于對Dispatch的消息檢查,則可以通過IServiceBehavior,IEndpointBehavior或 IContractBehavior中DispatchRuntime的MessageInspectors添加;而對Client的消息檢查則可以通過 IEndpointBehavior或IContractBehavior中ClientRuntime的MessageInspectors添加(注 意,此時與IServiceBehavior無關,因為它不會作用于客戶端代理)。例如:

public class PrintMessageInspectorBehavior : IDispatchMessageInspector,IEndpointBehavior
??? {
??????? //略去IDispatchMessageInspector接口成員的實現;

??????? #region IEndpointBehavior Members
??????? public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
??????? {
??????????? //empty;
??????? }
??????? public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
??????? {
????????????? clientRuntime.MessageInspectors.Add(this);
??????? }
??????? public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
??????? {
??????????? endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
??????? }
??????? public void Validate(ServiceEndpoint endpoint)
??????? {
??????????? //empty;
??????? }
??????? #endregion
??? }

如果實現的是IServiceBehavior接口,則需要遍歷ApplyDispatchBehavior()方法中的ServiceHostBase對象:

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
?? foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
?? {
????? foreach (EndpointDispatcher endpointDispatcher in channelDispatcher .Endpoints)
????? {
????????? endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
????? }
?? }
}

注:IDispatchMessageInspector 接口的方法為BeforeSendReply()和AfterReceiveRequest();而IClientMessageInspector接口 的方法則為BeforeSendRequest()和AfterReceiveReply()。

轉載于:https://blog.51cto.com/wayfarer/280087

總結

以上是生活随笔為你收集整理的聚焦WCF行为的扩展的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。