定义创建WCF组件的工厂
对于本例来说,客户端和服务端需要的组件主要有四类,即消息编码器工厂、分发消息格式化器、客户端消息格式化器和操作调用器。我们通过具有如下定义的静态的工厂类ComponentBuilder来创建它们。我们调用操作行为DataContractSerializerOperationBehavior的GetFormatter方法来创建基于指定操作的消息格式化器。不过该方法是一个内部方法,所以我们是通过反射的方式来调用的。isProxy参数表示创建的是客户端消息格式化器(True)还是分发消息格式化器(False)。
消息编码器工厂通过基于文本编码方式绑定元素TextMessageEncodingBindingElement的CreateMessageEncoderFactory创建,传入的参数分别表示消息的版本和文本编码类型。我们采用SyncMethodInvoker以同步的方式进行操作的执行。由于SyncMethodInvoker是一个内部类型,所以我们不得不采用反射的方式来创建它。
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。
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的类型表示这个映射。
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
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: }