原文:WCF技术剖析之四:基于IIS的WCF服务寄宿(Hosting)实现揭秘

通过《再谈IIS与ASP.NET管道》的介绍,相信读者已经对IIS和ASP.NET的请求处理管道有了一个大致的了解,在此基础上去理解基于IIS服务寄宿的实现机制就显得相对容易了。概括地说,基于IIS的服务寄宿依赖于两个重要的对象:System.ServiceModel.Activation.HttpModuleSystem. ServiceModel.Activation.HttpHandler

一、通过HttpModule实现服务寄宿

在默认的情况下,基于IIS的服务寄宿是通过一个特殊的HttpModule实现的,其类型为System.ServiceModel.Activation.HttpModule,是一个定义在System.ServiceModel程序集中的内部类型。HttpModule的定义大体上如下面的代码所示,我们很清楚地看到其实现的原理:将实现WCF Service请求处理的逻辑注册到HttpApplication的PostAuthenticationRequest事件中。

   1: internal class HttpModule : IHttpModule
   2: {
   3:     //其他成员
   4:     public void Init(HttpApplication context)
   5:     {
   6:         context.PostAuthenticateRequest += new EventHandler(HttpModule.ProcessRequest);
   7:     }
   8:     private static void ProcessRequest(object sender, EventArgs e)
   9:     {
  10:         //服务请求处理实现
  11:     }
  12: }

System.ServiceModel.Activation.HttpModule是一个特殊的HttpModule,说它特别是因为当HttpModule注册到HttpApplication的PostAuthenticateRequest事件处理程序执行后,不会再将请求进一步分发给后续的请求处理步骤。换句话说,就HttpApplication从BeginRequest到EndRequest整个请求处理的生命周期来说,对于基于.svc文件的请求仅仅延续到PostAuthenticateRequest阶段。我们可以通过一种简单的方式来证明这一点。

假设我们有一个WCF服务需要通过IIS进行寄宿,并把WCF服务相应的.svc文件定义在一个对应于某个IIS虚拟目录的ASP.NET Website中。现在我们为之添加一个global.asax,在该global.asax,我通过如下的代码注册了HttpApplication处理请求的前三个事件:BeginRequest、AuthenticateRequest和PostAuthenticateRequest,当这3个事件触发后,将一段代表当前事件的名称写入EventLog中。

   1: <%@ Application Language="C#" %>
   2: <%@ Import Namespace= "System.Diagnostics"%>
   3: <script runat="server">
   4:    
   5:     void Application_BeginRequest(object sender, EventArgs e)
   6:     {
   7:         string message = string.Format("BeginRequest Event is raised at {0}", DateTime.Now);
   8:         EventLog.WriteEntry("Application", message, EventLogEntryType.Information);
   9:     }
  10:  
  11:     void Application_AuthenticateRequest(object sender, EventArgs e)
  12:     {   
  13:         string message =  string.Format("AuthenticateRequst Event is raised at {0}",DateTime.Now);
  14:         EventLog.WriteEntry("Application", message, EventLogEntryType.Information);
  15:     }
  16:  
  17:     void Application_PostAuthenticateRequest(object sender, EventArgs e)
  18:     {
  19:         string message = string.Format("PostAuthenticateRequest Event is raised at {0}", DateTime.Now);
  20:         EventLog.WriteEntry("Application", message, EventLogEntryType.Information);
  21:     }
  22: </script>

如果我们上面的说法成立的话,只有HttpApplication的最初3个事件被触发。此外,HttpModule注册的操作会先于定义在global.asax的Application_PostAuthenticateRequest方法执行,那么在整个服务调用过程中,只有Application_BeginRequest和Application_AuthenticateRequest这两个方法会被执行。这一点我们可以从EventLog得到证实。当我们通过执行案例7-2中的代表客户端应用程序后,EventLog中WindowsLog的Application分组中,会多出两个日志项目(之前已经将日志清空),如图1所示。

 

图1 通过Event Viewer查看添加的Event Log

日志的内容正是我们在Application_BeginRequest和Application_AuthenticateRequest方法中定义的日志文本。可见仅仅这两个方法被成功执行,Application_PostAuthenticateRequest方法却没有被执行。可以想象,后续的事件也不可能被触发,如图2所示。

 

图2 Event Log的详细内容

到现在为止,我们仅仅是介绍了如何处理基于.svc文件的请求,并没有说明.svc文件对应的WCF Service是如何被寄宿的。服务的寄宿发生在对服务.svc文件的第一次访问,具体的实现很简单:ServiceMode根据请求的目的地址加载相应的.svc文件,通过解析定义在<%ServiceHost%>指令的Factory和Service属性得到ServiceHostFactory和Service的类型(Factory默认为System.ServiceMode.ServiceHostFactory),通过反射创建继承自基类System.ServiceModel.Activation.ServiceHostFactoryBase的ServiceHostFactory对象。最后通过ServiceHostFactory创建的继承自基类System.ServiceModel.ServiceHostBase的ServieHost对象对Serivce进行寄宿。

二、ASP.NET并行(Side by Side)模式

对于基于IIS服务寄宿,System.ServiceModel.Activation.HttpModule将基于.svc的请求劫持并分发给WCF的服务模型,从而结束了请求在ASP.NET管道的旅程。除了ASP.NET提供的一些少量的底层服务,比如动态编译和AppDomain管理等,绝大部分ASP.NET对传统的ASP.NET资源的请求处理机制将不会应用在基于WCF Service的请求处理流程中。从这个意义上讲,我们可以说WCF Service的运行模式和ASP.NET运行时采用的是一种并行的模式。

你完全可以用一个映射到某个IIS虚拟目录的ASP.NET Website同时作为asmx Web Service和.svc WCF Service的宿主。在这种情况下,ASP.NET .aspx Page、.asmx Web Service和WCF service运行在同一个AppDomain中。但是HttpRuntime对于.aspx Page和.asmx Web Service的处理机制并不会应用于对.svc WCF Service请求。我们把WCF Service这种寄宿模式称为ASP.NET并行(Side by Side)模式,图3揭示了这种寄宿模式。

 

图3 ASP.NET并行模式

在图3体现的这种情况下(ASP.NET .aspx Page和.svc WCF Service共存于同一个AppDomain),.aspx可以直接定位WCF Service,它们之间还可以共享一个基于AppDomain的状态,比如类型的静态属性。但是很多ASP.NET特性将不能被WCF Service使用,比如:

  • HttpContext对于WCF Service来说,HttpContext.Current永远为null;
  • 基于文件或者Url的授权:基于.svc文件的ACL(Access Control List)的授权和ASP.NET通过<authorization>定义的基于URL的授权都将失去效力。原因很简单,System.ServiceModel.Activation.HttpModule在PostAuthenticateRequest阶段就将请求劫持,而授权(Authorization)发生在PostAuthenticateRequest之后;
  • HttpModule扩展:作用于PostAuthenticateRequest事件后期的HttpModule将不会生效;
  • 身份模拟(Impersonation):即使通过配置<identity impersonate=”true” />允许身份模拟,WCF Service总是运行在IIS进程账号下。

不过,WCF服务模型通过自己的方式解决了上面的问题,比如:

  • OperationContext:ASP.NET HttpContext是基于当前的请求,WCF的OperationContext是基于当前的操作,本质上是一样的基于上下文的容器;
  • ServiceAuthorizationBehaviorServiceAuthorizationBehavior是一个Service行为,用于实现WCF的授权;
  • DispatchMessageInspector + 自定义Channel:DispatchMessageInspector和自定义Channel分别在服务模型和信道层对入栈消息进行额外的筛选和处理,和自定义HttpModule异曲同工;
  • 基于操作的身份模拟(Impersonation):WCF自身也提供了基于操作的身份模拟实现。

为什么WCF要采用这种于ASP.NET并行的模式,而不像Web Service一样采用与ASP.NET完全兼容呢?这主要是因为WCF和.asmx Web Service有本质的区别:Web Service总是采用IIS寄宿,并使用HTTP作为传输,而WCF则具有不同的寄宿方式,对于传输协议的选择也没有限制。在默认的情况下,不论采用何种寄宿方式,WCF本身的行为应该保持一致。所以,让WCF 服务的行为独立于寄宿的环境与传输协议,是采用并行模式的主要原因。

三、ASP.NET兼容模式

虽然在默认的情况下,IIS的寄宿采用ASP.NET并行的模式。但是在一个Web应用中,尤其是一些AJAX的Web应用,却明确地需要以一种ASP.NET兼容模式处理WCF Service请求。比如,在WCF Service的操作中,需要获取ASP.NET应用的SessionState,或者是需要通过基于.svc文件的ACL对WCF Service进行授权等。

WCF对此提供了支持,实现起来也很简单,对于编程来说,仅仅需要在Service类型加上一个特殊的AspNetCompatibilityRequirementsAttribute特性,并将RequirementsMode属性指定为AspNetCompatibilityRequirementsMode.Allowed,实例代码如下:

   1: [AspNetCompatibilityRequirements(
   2: RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
   3: public class CalculatorService:ICalculator
   4: {  
   5:     //省略成员
   6: }

除此之外,WCF的配置也需要做一些修改,我们需要将<serviceHostingEnvironment/>配置节的aspNetCompatibilityEnabled属性设为true。

   1: <?xml version="1.0"?>
   2: <configuration>
   3: <system.serviceModel>    
   4:     <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
   5:     <!—其他配置-->
   6:   </system.serviceModel>
   7: </configuration>

在ASP.NET兼容模式下,ASP.NET将会采用与处理.aspx、asmx一样的方式来处理基于.svc的请求,对WCF Service请求的处理将会贯穿HttpApplication请求处理的整个生命周期(从BeginRequest到EndRequest)。对于ASP.NET兼容模式,System.ServiceModel. Activation.HttpModule将忽略对HttpApplication对象PostAuthenticateRequest事件的注册,原本实现在HttpModule中对WCF Service的请求处理逻辑将被一个HttpHandler中:System.ServiceModel.Activation.HttpHandler。如同System.Web.UI.Page(本质上是一个HttpHandler)负责最终处理对.aspx的请求一样,System.ServiceModel.Activation.HttpHandler服务负责最终对.svc的请求。HttpHandler是一个定义在System.ServiceModel程序集中的内部类型。HttpHandler的定义如下,请求处理实现在ProcessRequest方法中,具体的逻辑与实现在System.ServiceModel.Activation.HttpModule中的是完全一致的。

   1: internal class HttpHandler : IHttpHandler, IRequiresSessionState
   2: {
   3:     public HttpHandler();
   4:     public void ProcessRequest(HttpContext context);
   5:  
   6:     public bool IsReusable { get; }
   7: }

作者:Artech
出处:http://artech.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

WCF技术剖析之四:基于IIS的WCF服务寄宿(Hosting)实现揭秘相关推荐

  1. WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序)...

    WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序) 原文:WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模 ...

  2. WCF技术剖析之二十一:WCF基本异常处理模式[中篇]

    通过WCF基本的异常处理模式[上篇], 我们知道了:在默认的情况下,服务端在执行某个服务操作时抛出的异常(在这里指非FaultException异常),其相关的错误信息仅仅限于服务端可见,并不会被WC ...

  3. WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇)

    [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话)]]在.NET中,所有的集合都实现了IEnumerable接口,比如Arra ...

  4. WCF技术剖析(卷1)正式出版

    [书     名] WCF技术剖析(卷1) [作     者] 蒋金楠 [出     版] 电子工业出版社 [书     号] 9787121089985 [出版日期] 2009 年7月 [开     ...

  5. WCF技术剖析之十四:泛型数据契约和集合数据契约(上篇)

    在.NET Framework 2.0中,泛型第一次被引入.我们可以定义泛型接口.泛型类型.泛型委托和泛型方法.序列化依赖于真实具体的类型,而泛型则刻意模糊了具体类型概念.而集合代表一组对象的组合,集 ...

  6. WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用

    如果一个类型,不一定是数据契约,和给定的数据契约具有很大的差异,而我们要将该类型的对象序列化成基于数据契约对应的XML.反之,对于一段给定的基于数据契约的XML,要通过反序列化生成该类型的对象,我们该 ...

  7. WCF技术剖析之三:如何进行基于非HTTP的IIS服务寄宿

    原文:[原创]WCF技术剖析之三:如何进行基于非HTTP的IIS服务寄宿 在上面一篇文章中,我们对不同版本的IIS,以及ASP.NET得的实现机制进行了详细而深入的分析.在介绍IIS7.0的时候,我们 ...

  8. [原创]WCF技术剖析之三:如何进行基于非HTTP的IIS服务寄宿

    在上面一篇文章中,我们对不同版本的IIS,以及ASP.NET得的实现机制进行了详细而深入的分析.在介绍IIS7.0的时候,我们谈到,HTTP.SYS+W3SVC实现了基于HTTP的请求监听,在此基础上 ...

  9. WCF技术剖析之六:为什么在基于ASP.NET应用寄宿(Hosting)下配置的BaseAddress无效...

    WCF技术剖析之六:为什么在基于ASP.NET应用寄宿(Hosting)下配置的BaseAddress无效 原文:WCF技术剖析之六:为什么在基于ASP.NET应用寄宿(Hosting)下配置的Bas ...

  10. WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化

    在本篇文章中,我们将讨论WCF四大契约(服务契约.数据契约.消息契约和错误契约)之一的消息契约(Message Contract).服务契约关注于对服务操作的描述,数据契约关注于对于数据结构和格式的描 ...

最新文章

  1. 利用Comet4J 及时推送消息
  2. 关于SAP Spartacus重载(override)UserAuthenticationTokenService的问题
  3. 完整机器学习项目的流程
  4. java对mysql的简单操作的综合运用——登录系统
  5. java web请求转发_Javaweb请求转发及重定向实现详解
  6. 网页视频之win7家庭版配置IIS
  7. 如何绕过mac地址过滤_Maccms V8 后台Getshell #2(绕过过滤)
  8. css动画旋转加平移实现3D图片墙
  9. C. Mortal Kombat Tower
  10. android微信连wifi设置,微信小程序实现连接wifi功能的方法
  11. 网站被劫持,打开一个网站会跳到另一个怎么办,直接输入网址也是这样。怎么办呢?
  12. GoogleTest系列:TEST_P的基本用法
  13. 深度:老年旅游市场迎来转折点,50/60新老年消费升级带来结构性创新机会—营销/产品/运营
  14. 【C4D】材质+渲染自学宝典(纯干货)
  15. 熵(entropy)的定义
  16. 一缕黑暗中的火光-----------顺序图--------------优雅的建模语言
  17. 用程序写入到TREEVIEW 怎样在aspx实现象ie收藏夹那样的功能
  18. python opencv 校准鱼眼相机
  19. git 出现错误 Could not resolve host: github.com 或者 gitlab.com 或者gerrit相关( 自有服务 )...
  20. 保研笔记一 软件工程与计算卷二(1-7章)

热门文章

  1. CURL+preg_match()
  2. Go gorilla websocket 小试牛刀
  3. textbox 下拉模糊查询ajax,Ajax实现在textbox中输入内容,动态从数据库中模糊查询显示到下拉框中...
  4. html页面 request,HTML DOM requestFullscreen() 方法
  5. apt安装openjdk8
  6. 编程基本功:while/for循环中,如果有switch,注意break是中断的哪一层
  7. 编译OpenJDK8 arm32的源码库
  8. LINUX虚拟机安装增强功能
  9. 脚本比别人的代码都多
  10. python中给文件改名