【转】WCF扩展系列 - 行为扩展(Behaviors)
原文:https://www.cnblogs.com/Creator/archive/2011/05/21/2052687.html
这个系列的第一部分将会重点关注WCF行为(behaviors),WCF提供了四种类型的行为:服务行为、终结点行为、契约行为和操作行为。这些行为的接口几乎是所有WCF的扩展入口。本篇文章只是对行为拓展讲述一些基础的铺设,具体到上面四个行为的扩展以及使用案例,将会在后续的文章中讲到.
Behaviors
上述这四个行为的所定义的接口分别是IServiceBehavior,IEndpointBehavior,IContractBehavior以及 IOperationBehavior。虽然是四个不同的接口,但它们的接口方法却基本相同,分别为 AddBindingParameters(),ApplyClientBehavior()以及ApplyDispatchBehavior()。注意,IServiceBehavior由于只能作用在服务端,因此并不包含ApplyClientBehavior()方法。
public interface I[Service/Endpoint/Contract/Operation]Behavior {
void Validate(DescriptionObject);
void AddBindingParameters(DescriptionObject, BindingParameterCollection);
void ApplyDispatchBehavior(DescriptionObject, RuntimeObject);
void ApplyClientBehavior(DescriptionObject, RuntimeObject); // not on IServiceBehavior
}
其中的方法描述如下:
- AddBindingParameters:用于向绑定元素传递自定义数据,以支持协定实现。
- Validate:用于检查服务宿主和服务说明,从而确定服务是否可成功运行。
- Apply[Client/Dispatch]Behavior:这是我们可以引用和修改WCF运行时对象的地方,也是用得最多的行为方法(大部分情况,上两个方法都会留空)。用于更改运行时属性值或插入自定义扩展对象(例如错误处理程序、消息或参数拦截器、安全扩展以及其他自定义扩展对象)。
他们各自的作用范围如下图所示(引用自张逸):
增加一个行为(behaviors )
向WCF中增加行为有三种不同的方法:
-
代码:service / endpoint / contract / operation 的描述类有一个behaviors集合属性,我们可以通过他简单的增加一个行为,具体做法,先将自定义服务行为添加到 Behaviors 属性,然后对 System.ServiceModel.ServiceHost 对象调用 ICommunicationObject.Open 方法。
-
配置文件:通过配置文件system.serviceModel/behaviors 节点,我们可以指定service behaviors 和 endpoint behaviors,已达到添加行为的目的
-
特性: 添加行为的简单方法是使用特性 — — 除了终结点行为。通过创建特性类 (基类型 = = System.Attribute) 和实现其中一个行为接口,您可以将特性应用于适当的元素,并添加行为到元素的描述。下面的代码显示了一个简单的服务,基于特性的行为的添加以及输出它们的调用顺序 (以及通过代码添加终结点行为)。
using System; using System.Collections.ObjectModel; using System.Reflection; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; namespace Behaviors { class MyServiceBehaviorAttribute : Attribute, IServiceBehavior { public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { Console.WriteLine("Inside {0}.{1}", this.GetType().Name, MethodBase.GetCurrentMethod().Name); } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { Console.WriteLine("Inside {0}.{1}", this.GetType().Name, MethodBase.GetCurrentMethod().Name); } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { Console.WriteLine("Inside {0}.{1}", this.GetType().Name, MethodBase.GetCurrentMethod().Name); } } class MyEndpointBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { Console.WriteLine("Inside {0}.{1}, endpoint {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, endpoint.Name); } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { Console.WriteLine("Inside {0}.{1}, endpoint {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, endpoint.Name); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { Console.WriteLine("Inside {0}.{1}, endpoint {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, endpoint.Name); } public void Validate(ServiceEndpoint endpoint) { Console.WriteLine("Inside {0}.{1}, endpoint {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, endpoint.Name); } } class MyContractBehaviorAttribute : Attribute, IContractBehavior { public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { Console.WriteLine("Inside {0}.{1}, contract {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, contractDescription.ContractType.Name); } public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime) { Console.WriteLine("Inside {0}.{1}, contract {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, contractDescription.ContractType.Name); } public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime) { Console.WriteLine("Inside {0}.{1}, contract {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, contractDescription.ContractType.Name); } public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) { Console.WriteLine("Inside {0}.{1}, contract {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, contractDescription.ContractType.Name); } } class MyOperationBehaviorAttribute : Attribute, IOperationBehavior { public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { Console.WriteLine("Inside {0}.{1}, operation {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, operationDescription.Name); } public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { Console.WriteLine("Inside {0}.{1}, operation {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, operationDescription.Name); } public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) { Console.WriteLine("Inside {0}.{1}, operation {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, operationDescription.Name); } public void Validate(OperationDescription operationDescription) { Console.WriteLine("Inside {0}.{1}, operation {2}", this.GetType().Name, MethodBase.GetCurrentMethod().Name, operationDescription.Name); } } [ServiceContract] [MyContractBehavior] public interface ITest { [OperationContract] [MyOperationBehavior] int Add(int x, int y); [OperationContract] int Multiply(int x, int y); } [ServiceContract] [MyContractBehavior] public interface ITest2 { [OperationContract] [MyOperationBehavior] string Echo(string text); } [MyServiceBehavior] public class Service : ITest, ITest2 { public int Add(int x, int y) { return x + y; } public int Multiply(int x, int y) { return x * y; } public string Echo(string text) { return text; } } class Program { static void Main(string[] args) { string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); ServiceEndpoint ep1 = host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "basic"); ep1.Name = "Endpoint1-BasicHttp"; ep1.Behaviors.Add(new MyEndpointBehavior()); ServiceEndpoint ep2 = host.AddServiceEndpoint(typeof(ITest2), new WSHttpBinding(), "ws"); ep2.Name = "Endpoint2-WSHttp"; ep2.Behaviors.Add(new MyEndpointBehavior()); Console.WriteLine("Opening the host..."); host.Open(); Console.WriteLine("Host opened"); } } }
我并不认为这就是“最优”的添加方法,他只是描述通过特性增加行为的一个特定的例子而已,具体什么是“最优”的添加行为的方法呢?其实这就像软件架构一样,永远没有最好的架构,只有最合适的架构。所以具体项目里面采用哪种方式去添加来得具体情况具体分析。个人比较喜欢用使用配置文件添加的方法….