WCF4.0进阶系列—第十一章 编写代码控制配置和通信(中)
摘要
检查消息
1 using System.ServiceModel.Dispatcher;
2 using System.ServiceModel.Description;
3. 修改ShoppingCartInspector类的定义,使其实现IDispatchMessageInspector接口
1 public class ShoppingCartInspector : IDispatchMessageInspector
2 {
3 }
IDispatchMessageInspector接口定义两个方法,使用这两个方法你可以查看和修改进入和离开服务的消息。
4. 在IDispatchMessageInspector上面点击右键,指向实现接口à实现接口。Visual Studio自动生成IDispatchMessageInspector接口的两个方法。一个名为AfterReceiveRequest,在服务的方法被访问之前调用该方法;另外一个为BeforeSendReply,在服务的方法结束之前调用该方法。请注意两个方法的第一个参数都是Message对象类型。该参数的值为刚刚收到或者即将发出的消息对象。你在方法里可以修改该消息对象的内容,你对该对象所作的改动都将传递至服务或者返回到客户端,这取决于该消息是客户端发送的请求消息还是服务的响应消息。由于这个原因,你在修改消息时应格外小心,不要做了相反的修改。
5. 修改Visual Studio生成的AfterReceiveRequest方法的内容
1 public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request,
2 System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
3 {
4 Console.WriteLine("Message received: {0}\n{1}\n\n", request.Headers.Action, request.ToString());
5 return null;
6 }
第一行代码显示消息的行为和消息的内容。在某些情况下,关联AfterReceiveRequest方法的消息和BeforeSendReply方法的消息是非常有用的。如果你查看BeforeSendReply方法,你可以看到该方法的第二个参数为correlationState。如果你需要关联请求和响应消息,你可以在AfterReveiveRequest方法中创建一个唯一的标识符并返回改值。WCF运行时将把相同的标识符作为参数传递至方法BeforeSendReplyMethod。在当前的练习中,你没有关联任何请求和回复消息,所以AfterReceiveRequest方法将返回null。
1 public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
2 {
3 Console.WriteLine("Message sent: {0}\n{1}\n\n", reply.Headers.Action, reply.ToString());
4 }
7. 重新生成ShoppingCartService方案
创建自定义行为
- AddingBindingParameters,一些行为可以接收额外的数据项作为参数,并传递至绑定元素,管理员或者开发人员可以在BindingParameterCollection中提供这些信息并将这些信息传递至该方法。WCF运行时针对服务侦听的每个URI都调用一次AddingBindingParameters方法。
- ApplyDispatcherBehavior, 使用该方法,你可以修改ServiceHost对象所寄宿服务的行为。ServiceHost对象被作为该方法的第二个参数传入。使用该方法可以执行的任务包括添加自定义错误处理,或者消息检查对象。
- Validate, WCF运行时调用该方法以验证服务是否满足你自己定义的需求。比如,你可以检查该方法的第一个参数(传入的服务描述对象),如果该服务的合约与期望的不一致,你可以拒绝并抛出一个异常。
public class ShoppingCartBehavior : IServiceBehavior
2. 在IServiceBehavior上点击右键,指向实现接口à实现接口。 Visual Studio将自动生成AddBindingParameters、ApplyDispatcherBehavior和Validate方法
4. 修改ApplyDispatcherBehavior方法
1 public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
2 System.ServiceModel.ServiceHostBase serviceHostBase)
3 {
4 foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
5 {
6 foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
7 {
8 endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new ShoppingCartInspector());
9 }
10 }
11 }
上都代码首先迭代ChannelDispatchers;然后再迭代每个ChannelDispatcher的EndpointDispatcher;然后添加ShoppingCartInspector对象到每个EndpointDispatcher上。随后,当一个EndpointDispatcher对象分发一个服务方法或者一个服务方法返回到EndpointDispatcher对象,消息都将通过ShoppingCartInspector对象传输。
1 static void Main(string[] args)
2 {
3 ...
4 ServiceHost host = new ServiceHost(typeof(ShoppingCartService.ShoppingCartService));
5 host.AddServiceEndpoint(typeof(ShoppingCartService.IShoppingCartService), customBinding, "net.tcp://localhost:8090/ShoppingCartService");
6
7 host.Description.Behaviors.Add(new ShoppingCartService.ShoppingCartBehavior());
8
9 host.Open();
10 ...
11 }
6. 在非调适模式下,运行解决方案。当服务启动后,在客户端控制台窗口中按ENTER键。
定义行为扩展元素
using System.ServiceModel.Configuration;
3. 添加一个名为ShoppingCartBehaviorExtensionElement的public类,该类继承BehaviorExtensionElement类
1 public override Type BehaviorType
2 {
3 get { return typeof(ShoppingCartBehavior); }
4 }
5. 在ShoppingCartBehaviorExtensionElement中,重写CreateBehavior方法
protected override object CreateBehavior()
{
return new ShoppingCartBehavior();
}
1 static void Main(string[] args)
2 {
3 ...
4 ServiceHost host = new ServiceHost(typeof(ShoppingCartService.ShoppingCartService));
5 host.AddServiceEndpoint(typeof(ShoppingCartService.IShoppingCartService), customBinding, "net.tcp://localhost:8090/ShoppingCartService");
6
7 //host.Description.Behaviors.Add(new ShoppingCartService.ShoppingCartBehavior());
8
9 host.Open();
10 ...
11 }
3. 使用服务配置管理工具打开app.config
4. 在配置面板,展开高级文件夹,然后展开扩展节点,然后点击行为元素扩展
5. 在行为元素扩展面板的底部,点击"创建"按钮。在扩展配置元素编辑对话框中的Name处输入messageInspector。
1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3 <connectionStrings>
4 <add name="AdventureWorksEntities" connectionString="metadata=res://*/ProductsModel.csdl|res://*/ProductsModel.ssdl|res://*/ProductsModel.msl;provider=System.Data.SqlClient;provider connection string="data source=localhost;initial catalog=AdventureWorks;integrated security=False; user id=ap_wcf; password=ap_wcf; multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
5 </connectionStrings>
6
7 <system.serviceModel>
8 <behaviors>
9 <serviceBehaviors>
10 <behavior>
11 <messageInspector />
12 </behavior>
13 </serviceBehaviors>
14 </behaviors>
15 <extensions>
16 <behaviorExtensions>
17 <add name="messageInspector" type="ShoppingCartService.ShoppingCartBehaviorExtensionElement, ShoppingCartService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
18 </behaviorExtensions>
19 </extensions>
20 </system.serviceModel>
21 </configuration>
12. 在非调适模式下运行解决方案。在ShoppingCartClient控制台中,按ENTER键。客户端程序和服务将和前一个练习的结果一致。在寄宿服务的控制台窗口中显示了ShoppingCartInspector对象输出的消息。