`
varsoft
  • 浏览: 2430042 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

[原创]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事件中。

<style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style>
   1: internal class HttpModule : IHttpModule
<!--CRLF-->
   2: {
<!--CRLF-->
   3:     //其他成员
<!--CRLF-->
   4:     public void Init(HttpApplication context)
<!--CRLF-->
   5:     {
<!--CRLF-->
   6:         context.PostAuthenticateRequest += new EventHandler(HttpModule.ProcessRequest);
<!--CRLF-->
   7:     }
<!--CRLF-->
   8:     private static void ProcessRequest(object sender, EventArgs e)
<!--CRLF-->
   9:     {
<!--CRLF-->
  10:         //服务请求处理实现
<!--CRLF-->
  11:     }
<!--CRLF-->
  12: }
<!--CRLF-->

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中。

<style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style>
   1: <%@ Application Language="C#" %>
<!--CRLF-->
   2: <%@ Import Namespace= "System.Diagnostics"%>
<!--CRLF-->
   3: <script runat="server">
<!--CRLF-->
   4:    
<!--CRLF-->
   5:     void Application_BeginRequest(object sender, EventArgs e)
<!--CRLF-->
   6:     {
<!--CRLF-->
   7:         string message = string.Format("BeginRequest Event is raised at {0}", DateTime.Now);
<!--CRLF-->
   8:         EventLog.WriteEntry("Application", message, EventLogEntryType.Information);
<!--CRLF-->
   9:     }
<!--CRLF-->
  10: 
<!--CRLF-->
  11:     void Application_AuthenticateRequest(object sender, EventArgs e)
<!--CRLF-->
  12:     {   
<!--CRLF-->
  13:         string message =  string.Format("AuthenticateRequst Event is raised at {0}",DateTime.Now);
<!--CRLF-->
  14:         EventLog.WriteEntry("Application", message, EventLogEntryType.Information);
<!--CRLF-->
  15:     }
<!--CRLF-->
  16: 
<!--CRLF-->
  17:     void Application_PostAuthenticateRequest(object sender, EventArgs e)
<!--CRLF-->
  18:     {
<!--CRLF-->
  19:         string message = string.Format("PostAuthenticateRequest Event is raised at {0}", DateTime.Now);
<!--CRLF-->
  20:         EventLog.WriteEntry("Application", message, EventLogEntryType.Information);
<!--CRLF-->
  21:     }
<!--CRLF-->
  22: </script>
<!--CRLF-->

如果我们上面的说法成立的话,只有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,实例代码如下:

<style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style>
   1: [AspNetCompatibilityRequirements(
<!--CRLF-->
   2: RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
<!--CRLF-->
   3: public class CalculatorService:ICalculator
<!--CRLF-->
   4: {  
<!--CRLF-->
   5:     //省略成员
<!--CRLF-->
   6: }
<!--CRLF-->

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

<style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style>
   1: <?xml version="1.0"?>
<!--CRLF-->
   2: <configuration>
<!--CRLF-->
   3: <system.serviceModel>    
<!--CRLF-->
   4:     <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<!--CRLF-->
   5:     <!—其他配置-->
<!--CRLF-->
   6:   </system.serviceModel>
<!--CRLF-->
   7: </configuration>
<!--CRLF-->

在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中的是完全一致的。

<style type="text/css">.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style>
   1: internal class HttpHandler : IHttpHandler, IRequiresSessionState
<!--CRLF-->
   2: {
<!--CRLF-->
   3:     public HttpHandler();
<!--CRLF-->
   4:     public void ProcessRequest(HttpContext context);
<!--CRLF-->
   5: 
<!--CRLF-->
   6:     public bool IsReusable { get; }
<!--CRLF-->
   7: }
<!--CRLF-->

注:部分内容节选自《WCF技术剖析(卷1)》第七章:客服务寄宿(Service Hosting)

WCF技术剖析系列:

WCF技术剖析之一:通过一个ASP.NET程序模拟WCF基础架构
WCF技术剖析之二:再谈IIS与ASP.NET管道
WCF技术剖析之三:如何进行基于非HTTP的IIS服务寄宿
WCF技术剖析之四:基于IIS的WCF服务寄宿(Hosting)实现揭秘
WCF技术剖析之五:利用ASP.NET兼容模式创建支持会话(Session)的WCF服务
WCF技术剖析之六:为什么在基于ASP.NET应用寄宿(Hosting)下配置的BaseAddress无效
WCF技术剖析之七:如何实现WCF与EnterLib PIAB、Unity之间的集成
WCF技术剖析之八:ClientBase<T>中对ChannelFactory<T>的缓存机制
WCF技术剖析之九:服务代理不能得到及时关闭会有什么后果?
WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理

WCF技术剖析之十一:异步操作在WCF中的应用(上篇)
WCF技术剖析之十一:异步操作在WCF中的应用(下篇)
WCF技术剖析之十二:数据契约(Data Contract)和数据契约序列化器(DataContractSerializer)
WCF技术剖析之十三:序列化过程中的已知类型(Known Type)
WCF技术剖析之十四:泛型数据契约和集合数据契约(上篇)
WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇)
WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用
WCF技术剖析之十六:数据契约的等效性和版本控制


分享到:
评论

相关推荐

    WCF 自身寄宿和IIS寄宿

    本个程序,是编写WCF的两种寄宿,第一种是自身寄宿,第二种是IIS寄宿。 在运行 自身寄宿的时候,先运行 Hosting, 在运行 Client。 其二是 IIS寄宿,首先 IISService ,这是一个配置后的,服务,可以吧 IISService...

    WCF技术剖析,wcf教程+.pdf

    蒋金楠老师的wcf教程,个人看了,觉得写的很不错,对刚入门和深入了解wcf都适用,有需要的同学可下载学习

    WCF技术剖析pdf

    WCF技术剖析

    WCF开发实战

    WCF开发实战系列一:创建第一个WCF服务 WCF开发实战系列二:使用IIS发布WCF服务 WCF开发实战系列三:自运行WCF服务 WCF开发实战系列四:使用Windows服务发布WCF服务 WCF开发实战系列五:创建WCF客户端程序

    我的WCF之旅源代码 IIS寄宿

    我的WCF之旅(1)配套代码,IIS寄宿 泛型 序列化

    完整版 设计模式:基于C#的工程化实现及扩展

    完整扫描高清版 设计模式:基于C#的工程化...等,同时还有相对于其他设计模式而言较新的.NET Framework实现技术,如泛型、3.0的WCF等。本书以C#展现多个不同用途的模式,还提供了日后可重复验证与测试的单元测试码。

    Apress Pro WCF 4

    ■Chapter 5: Hosting and Consuming WCF Services ■Chapter 6: Managing WCF Services Part III: Advanced Topics in WCF ■Chapter 7: Implementing WCF Security ■Chapter 8: Implementing Reliable ...

    WCF技术剖析(卷1)

    WCF技术剖析(卷1),是一本非常专业的不错的WCF技术类的书籍。

    无svc文件发布WCF服务到IIS上

    1,先手动添加一个类库,然后在里面加上你的契约与服务如例子中的WCFServices项目 2,新建一个 ASP.NET空网站 3,在网站上引用你第一步加的类库 4,配置Web.config文件 5,发布网站 6,将其部署到IIS上 ...

    WCF技术剖析.pdf

    同时本书从WCF的服务端框架和客户端框架进行深层次的剖析,介绍了服务寄宿和服务调用;对实例化和会话进行了讨论,从服务实例的激活和客户端状态保持两个侧面详细介绍WCF的实例上下文提供机制和基于会话信道的会话...

    部署WCF上IIS的步骤

    将WCF部署上IIS的步骤与silverlight浏览的安装文件

    IIS部署WCF服务

    一篇中,我们创建了一个简单的WCF服务,在测试的时候,我们使用VS2008自带的WCFSVCHost(WCF服务主机)发布WCF服务,以便进行测试。这种VS2008内置的WCFSVCHost只适用于开发人员测试的使用,能进行WCF服务部署。这一篇...

    WCF例程寄宿WINDOWS服务

    WCF例程,寄宿WINDOWS服务,WINFORM调用。

    WCF服务寄宿在Form中

    实现了WCF服务寄宿在WinForm中,并创建了一个Console客户端采用并发进行调用。 涉及范围:WCF服务、寄宿、并发调用机制 备注:基于VS2010开发,运行环境要求.net4.0

    [WCF系列] WCF 技术揭秘 (微软出品) (英文版)

    [Microsoft Press] WCF 技术揭秘 (微软出品) [Microsoft Press] Inside Windows Communication Foundation (E-Book) ☆ 出版信息:☆ [作者信息] Justin Smith [出版机构] Microsoft Press [出版日期] 2007年05...

    WCF技术专题:WCF入门与进阶

    讲解WCF技术的,适合各种阶段的学习。从入门到进阶。

    WCF服务的控制台程序寄宿案例

    该资源为WCF服务寄宿于控制台应用程序的案例,展示了如何编写WCF服务,开启WCF并且调用WCF服务等内容。

    如何在windows服务中寄宿wcf服务的例子

    如何在windows服务中寄宿wcf服务的例子

    WCF建立在IIS服务上实现加,减,乘,除,小程序

    WCF建立在IIS服务上实现加,减,乘,除,小程序WCF建立在IIS服务上实现加,减,乘,除,小程序

Global site tag (gtag.js) - Google Analytics