技术开发 频道

通过模拟程序 解析WCF大致的执行流程

  定义创建WCF组件的工厂

  对于本例来说,客户端和服务端需要的组件主要有四类,即消息编码器工厂、分发消息格式化器、客户端消息格式化器和操作调用器。我们通过具有如下定义的静态的工厂类ComponentBuilder来创建它们。我们调用操作行为DataContractSerializerOperationBehavior的GetFormatter方法来创建基于指定操作的消息格式化器。不过该方法是一个内部方法,所以我们是通过反射的方式来调用的。isProxy参数表示创建的是客户端消息格式化器(True)还是分发消息格式化器(False)。

  消息编码器工厂通过基于文本编码方式绑定元素TextMessageEncodingBindingElement的CreateMessageEncoderFactory创建,传入的参数分别表示消息的版本和文本编码类型。我们采用SyncMethodInvoker以同步的方式进行操作的执行。由于SyncMethodInvoker是一个内部类型,所以我们不得不采用反射的方式来创建它。

   1: public static class ComponentBuilder
  
2: {
  
3:     public static object GetFormatter(OperationDescription operation, bool isProxy)
  
4:     {
  
5:         bool formatRequest = false;
  
6:         bool formatReply = false;
  
7:         DataContractSerializerOperationBehavior behavior = new DataContractSerializerOperationBehavior(operation);
  
8:         MethodInfo method = typeof(DataContractSerializerOperationBehavior).GetMethod("GetFormatter", BindingFlags.Instance | BindingFlags.NonPublic);
  
9:         return method.Invoke(behavior, new object[] { operation, formatRequest, formatReply, isProxy });
  
10:     }
  
11:
  
12:     public static MessageEncoderFactory GetMessageEncoderFactory(MessageVersion messageVersion, Encoding writeEncoding)
  
13:     {
  
14:         TextMessageEncodingBindingElement bindingElement = new TextMessageEncodingBindingElement(messageVersion, writeEncoding);
  
15:         return bindingElement.CreateMessageEncoderFactory();
  
16:     }
  
17:     public static IOperationInvoker GetOperationInvoker(MethodInfo method)
  
18:     {
  
19:         string syncMethodInvokerType = "System.ServiceModel.Dispatcher.SyncMethodInvoker, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
  
20:         Type type = Type.GetType(syncMethodInvokerType);
  
21:         return (IOperationInvoker)Activator.CreateInstance(type, new object[]{method});
  
22:     }
  
23: }

   定义HttpModule映射WcfHandler

  我们通过HttpModule的方式将用于处理WCF服务请求的映射到相应的WCF服务调用请求,为此我们定义了如下一个实现了System.Web.IHttpModule接口的WcfHttpModule类型。WcfHttpModule通过注册HttpApplication的BeginRequest事件的方式将创建的WcfHandler映射为处理当前HTTP请求的HttpHandler。

   1: public class WcfHttpModule: IHttpModule
  
2: {
  
3:     public void Dispose() {}
  
4:
  
5:     public void Init(HttpApplication context)
  
6:     {
  
7:         context.BeginRequest += (sender, args) =>
  
8:             {
  
9:                 string relativeAddress = HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.Remove(0,2);
  
10:                 Type serviceType = RouteTable.Routes.Find(relativeAddress);
  
11:                 if (null == serviceType)
  
12:                 {
  
13:                     return;
  
14:                 }
  
15:                 IHttpHandler handler = this.CreateHttpHandler(serviceType);
  
16:                 context.Context.RemapHandler(handler);
  
17:             };
  
18:     }
  
19:     protected IHttpHandler CreateHttpHandler(Type serviceType)
  
20:     {
  
21:         MessageEncoderFactory encoderFactory = ComponentBuilder.GetMessageEncoderFactory(MessageVersion.Default, Encoding.UTF8);
  
22:         WcfHandler handler = new WcfHandler(serviceType, encoderFactory);
  
23:         Type interfaceType = serviceType.GetInterfaces()[0];
  
24:         ContractDescription contract = ContractDescription.GetContract(interfaceType);
  
25:         foreach (OperationDescription operation in contract.Operations)
  
26:         {
  
27:             IDispatchMessageFormatter messageFormatter = (IDispatchMessageFormatter)ComponentBuilder.GetFormatter(operation, false);
  
28:             handler.MessageFormatters.Add(operation.Messages[0].Action, messageFormatter);
  
29:
  
30:             IOperationInvoker operationInvoker = ComponentBuilder.GetOperationInvoker(operation.SyncMethod);
  
31:             handler.OperationInvokers.Add(operation.Messages[0].Action, operationInvoker);
  
32:
  
33:             handler.Methods.Add(operation.Messages[0].Action, operation.SyncMethod);
  
34:         }
  
35:         return handler;
  
36:     }
  
37: }

   至于WcfHandler的创建,需要确定服务的类型。而服务的类型只能根据请求的地址来确定,这个IIS寄宿根据.svc文件来创建ServiceHost的原理是一样的。对于本例来说,我们需要对请求的地址和服务类型作一个映射,为此我们定义了如下一个RouteMapping的类型表示这个映射。

   1: public class RouteMapping
  
2: {
  
3:     public string Address { get; private set; }
  
4:     public Type ServiceType { get; private set; }
  
5:     public RouteMapping(string address, Type serviceType)
  
6:     {
  
7:         this.Address = address;
  
8:         this.ServiceType = serviceType;
  
9:     }
  
10: }

   而映射表则通过如下一个继承自Collection的RouteTable来定义。泛型的Register方法用于注册地址与服务类型的映射关系,而Find方法则根据地址获取相应的服务类型。静态属性Routes表示当前被使用的映射表,而在WcfHttpModule中正是通过这个静态属性根据解析出来的地址得到用于创建WcfHandler的服务类型的。

   1: public class RouteTable: Collection<RouteMapping>
  
2: {
  
3:     public static RouteTable Routes{get; private set;}
  
4:     static RouteTable()
  
5:     {
  
6:         Routes = new RouteTable();
  
7:     }      
  
8:     public Type Find(string address)
  
9:     {
  
10:         RouteMapping routeMapping =  (from route in this
  
11:                 where string.Compare(route.Address, address,true) == 0
  
12:                 select route).FirstOrDefault();
  
13:         return null == routeMapping? null: routeMapping.ServiceType;
  
14:     }
  
15:
  
16:     public void Register<T>(string address
)
  
17:     {
  
18:         this.Add(new RouteMapping(address, typeof(T)));
  
19:     }
  
20: }
1
相关文章