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

[原创]WCF技术剖析之五:利用ASP.NET兼容模式创建支持会话(Session)的WCF服务

阅读更多

在《基于IIS的WCF服务寄宿(Hosting)实现揭秘》中,我们谈到在采用基于IIS(或者说基于ASP.NET)的WCF服务寄宿中,具有两种截然不同的运行模式:ASP.NET并行(Side by Side)模式和ASP.NET兼容模式。对于前者,WCF通过HttpModule实现了服务的寄宿,而对于后者,WCF的服务寄宿通过一个HttpHandler实现。只有在ASP.NET兼容模式下,我们熟悉的一些ASP.NET机制才能被我们使用,比如通过HttpContext的请求下下文;基于文件或者Url的授权;HttpModule扩展;身份模拟(Impersonation)等。

由于在ASP.NET兼容模式下,ASP.NET采用与.aspx Page完全一样的方式处理基于.svc的请求,换言之,我们就可以借助当前HttpContext的SessionState维护会话状态,进而创建一个支持会话的WCF Service。接下来,我们就通过一个简单的例子,一步步地创建这样的会话服务。本案例采用如图1所示的3层结构。 (Source Code从这里下载)

图1 ASP.NET兼容模式案例应用结构

步骤一、定义服务契约:ICalculator

案例依然沿用计算服务的例子,不过通过原来直接与传入操作数并得到运算结果的方式不同,为了体现会话状态的存在,我们将本案例的WCF服务定义成“累积计算服务”:保留上一次运算的结果,并将其作为后续运算的操作数。为此,定义了如下一个接口作为服务契约:前面4个操作代表基本的加、减、乘、除运算,计算结果通过GetResult方法获得。

<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: using System.ServiceModel;
<!--CRLF-->
   2: namespace Artech.AspCompatibleServices.Contracts
<!--CRLF-->
   3: {
<!--CRLF-->
   4:     [ServiceContract]
<!--CRLF-->
   5:     public interface ICalculator
<!--CRLF-->
   6:     {
<!--CRLF-->
   7:         [OperationContract]
<!--CRLF-->
   8:         void Add(double x);
<!--CRLF-->
   9:         [OperationContract]
<!--CRLF-->
  10:         void Subtract(double x);
<!--CRLF-->
  11:         [OperationContract]
<!--CRLF-->
  12:         void Multiply(double x);
<!--CRLF-->
  13:         [OperationContract]
<!--CRLF-->
  14:         void Divide(double x);
<!--CRLF-->
  15:         [OperationContract]
<!--CRLF-->
  16:         double GetResult();
<!--CRLF-->
  17:     }
<!--CRLF-->
  18: }
<!--CRLF-->

步骤二、实现服务:CalculatorService

服务的实现和.svc都定义在一个ASP.NET Web站点项目中。对于定义在 CalculatorService中的每次运算,先通过HttpContext从SessionState中取出上一次运算的结果,完成运算后再将新的运算结果保存到SessionState中。通过在CalculatorService上应用AspNetCompatibilityRequirementsAttribute实现对ASP.NET兼容模式的支持。

<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: using System.ServiceModel.Activation;
<!--CRLF-->
   2: using System.Web;
<!--CRLF-->
   3: using Artech.AspCompatibleServices.Contracts;
<!--CRLF-->
   4: [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
<!--CRLF-->
   5: public class CalculatorService : ICalculator
<!--CRLF-->
   6: {
<!--CRLF-->
   7:     public void Add(double x)
<!--CRLF-->
   8:     {
<!--CRLF-->
   9:         HttpContext.Current.Session["__Result"] = GetResult() + x;
<!--CRLF-->
  10:     }
<!--CRLF-->
  11:     public void Subtract(double x)
<!--CRLF-->
  12:     {
<!--CRLF-->
  13:         HttpContext.Current.Session["__Result"] = GetResult() - x;
<!--CRLF-->
  14:     }
<!--CRLF-->
  15:     public void Multiply(double x)
<!--CRLF-->
  16:     {
<!--CRLF-->
  17:         HttpContext.Current.Session["__Result"] = GetResult() * x;
<!--CRLF-->
  18:     }
<!--CRLF-->
  19:     public void Divide(double x)
<!--CRLF-->
  20:     {
<!--CRLF-->
  21:         HttpContext.Current.Session["__Result"] = GetResult() / x;
<!--CRLF-->
  22:     }
<!--CRLF-->
  23:     public double GetResult()
<!--CRLF-->
  24:     {
<!--CRLF-->
  25:         if (HttpContext.Current.Session["__Result"] == null)
<!--CRLF-->
  26:         {
<!--CRLF-->
  27:             HttpContext.Current.Session["__Result"] = 0.0;
<!--CRLF-->
  28:         }
<!--CRLF-->
  29:         return (double)HttpContext.Current.Session["__Result"];
<!--CRLF-->
  30:     }
<!--CRLF-->
  31: }
<!--CRLF-->

下面是CalculatorService对应的.svc的定义和Web.config。为了简洁,在<@ServiceHost%>指令中,仅仅设置一个必需属性Service。对于ASP.NET兼容模式的支持,配置<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:     <services>
<!--CRLF-->
   6:       <service name="CalculatorService">
<!--CRLF-->
   7:         <endpoint binding="wsHttpBinding" contract="Artech.AspCompatibleServices.Contracts.ICalculator" />
<!--CRLF-->
   8:       </service>
<!--CRLF-->
   9:     </services>
<!--CRLF-->
  10:   </system.serviceModel>
<!--CRLF-->
  11: </configuration> 
<!--CRLF-->

步骤三、创建客户端:Client

CalculatorService的客户端应用通过一个Console应用程序模拟,其服务调用方式并无特别之处,下面是相关的代码和配置。

   1: using System;
<!--CRLF-->
   2: using System.ServiceModel;
<!--CRLF-->
   3: using Artech.AspCompatibleServices.Contracts;
<!--CRLF-->
   4: namespace Artech.AspCompatibleServices.Clients
<!--CRLF-->
   5: {
<!--CRLF-->
   6:     class Program
<!--CRLF-->
   7:     {
<!--CRLF-->
   8:         static void Main(string[] args)
<!--CRLF-->
   9:         {
<!--CRLF-->
  10:             using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("CalculatorService"))
<!--CRLF-->
  11:             {
<!--CRLF-->
  12:                 ICalculator proxy = channelFactory.CreateChannel(); 
<!--CRLF-->
  13:                 Console.WriteLine("初始值为: {0}", proxy.GetResult()); proxy.Add(1); 
<!--CRLF-->
  14:                 Console.WriteLine("Add(3)", proxy.GetResult()); 
<!--CRLF-->
  15:                 Console.WriteLine("运算结果为: {0}", proxy.GetResult()); proxy.Multiply(10);
<!--CRLF-->
  16:                 Console.WriteLine("Multiply(10)", proxy.GetResult()); Console.WriteLine("运算结果为: {0}", proxy.GetResult()); proxy.Subtract(2); 
<!--CRLF-->
  17:                 Console.WriteLine("Subtract(2)", proxy.GetResult()); Console.WriteLine("运算结果为: {0}", proxy.GetResult());
<!--CRLF-->
  18:             } Console.Read();
<!--CRLF-->
  19:         }
<!--CRLF-->
  20:     }
<!--CRLF-->
  21: }
<!--CRLF-->
   1: <?xml version="1.0" encoding="utf-8" ?>
<!--CRLF-->
   2: <configuration>
<!--CRLF-->
   3:     <system.serviceModel>
<!--CRLF-->
   4:         <client>
<!--CRLF-->
   5:             <endpoint  address="http://localhost/AspCompatibleServices/CalculatorService.svc"
<!--CRLF-->
   6:                 binding="wsHttpBinding" contract="Artech.AspCompatibleServices.Contracts.ICalculator"
<!--CRLF-->
   7:                 name="CalculatorService"/>
<!--CRLF-->
   8:         </client>            </system.serviceModel>
<!--CRLF-->
   9: </configuration>
<!--CRLF-->

但是,但我们运行客户端的程序,输出的结果并不像我们希望的那样。从下面的结果可以看出,每次通过GetResult()方法得到的结果都是0,也就是说,服务端并没有将运算结果保存下来。

   1: 初始值为:0
<!--CRLF-->
   2: Add(3)运算结果为:0
<!--CRLF-->
   3: Multiply(10)运算结果为:0
<!--CRLF-->
   4: Subtract(2)运算结果为:0
<!--CRLF-->

允许Cookie传递

要解释这个问题,得从Session的实现机制说起。众所周知,HTTP是无状态(Stateless)的传输协议,对服务端来说,它收到的每个HTTP请求都是全新的请求。ASP.NET会话(Session)的实现很简单,就是让每次HTTP请求携带Session的识别信息(Session ID),那么服务就可以根据此信息判断请求来自哪个客户端了。关于Session识别信息的保存,ASP.NET有两种方式:Cookie和URL,前者将其放到Cookie中,每次HTTP请求将会携带该Cookie的值,后者则将其作为请求URL的一部分。一般情况下采用基于Cookie的实现机制,如果Cookie禁用则采用后者。

那么对于ASP.NET兼容模式下的WCF也一样,要想让服务端能够识别会话,就需要让每个服务调用的HTTP请求携带Session的识别信息,我们也可以通过传递Cookie的方式来解决这个问题。对于WCF来说,Cookie传递能够通过Binding来控制,对于WsHttpBinding来说,默认情况下并不允许Cookie的传递。我们可以通过WsHttpBinding的AllowCookies来控制是否允许传递Cookie,该属性可以通过配置进行设置。为此,我们对客户端的配置进行了如下的修改。再次运行我们的案例程序,将会得到你期望的输出。

<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; } .cs
评论

相关推荐

    Pro C# 7: With .NET and .NET Core

    Entity Framework (EF) Core, and more, sits alongside the latest updates to .NET, including Windows Presentation Foundation (WPF), Windows Communication Foundation (WCF), and ASP.NET MVC. Dive in and...

    WCF Rest Service Example in Asp.net

    WCF Rest Service Example in Asp.net

    WCF+Asp.net

    WCF+Asp.net WCF+Asp.net WCF+Asp.net WCF+Asp.net WCF+Asp.net

    ASP.NET设计模式(中文带目录)

    演示如何使用GOF设计模式来改进ASP.NET代码说明如何在企业级ASP.NET站点中采用Fowler的企业模式详述如何对ASP.NET应用程序进行分层以及如何分离关注点和职责详述如何采用JQuery、JSON以及WCF消息传送模式来实现AJAX...

    支持ASP.NET Ajax的WCF服务

    WCF与Ajax开发实践系列课程(3):支持ASP.NET Ajax的WCF服务

    Asp.net Wcf学习(通用)

    目前最新的WCF版本是February 2006 CTP,下载页面是:http://www.microsoft.com/downloads/details.aspx?FamilyId=F51C4D96-9AEA-474F-86D3-172BFA3B828B&displaylang=en。使用WCF需要用到一些相关的工具,如SvcUtil...

    ASP.NET 4.0编程技术大全光盘

    C#语法知识、C#的面向对象特性、ASP.NET数据绑定技术、高级数据绑定控件、缓存和异步访问、LINQ语言集成查询、成员管理技术、自定义成员提供者、角色和授权、在ASP.NET中整合WCF编程、在ASP.NET中整合WF编程、HTTP...

    ASP.NET与WCF的调用

    ASP.NET调用用WCF编写的服务,WCF主要写后台数据处理部分。

    C# ASP.NET访问WCF实例

    这个DEMO演示了WINDOWS程序访问WCF和WEB程序访问WCF。 1、打开WcfDemo下面的解决方案,运行WINDOWS程序,启动WCF 2、打开WindowsFormsApplication2下面的解决方案,运行,即可查看效果 3、打开WebDemo下面的解决...

    一个基于ASP.NET AJAX+JavaScript 实现的WCF service 服务程序源码例子

    一个基于ASP.NET AJAX+JavaScript 实现的WCF service 服务程序源码例子。

    Asp.Net及相关技术介绍

    此PPT讲述了Asp.Net WebAPI及相关Web服务技术发展历史。 共80多页,Asp.Net WebAPI在讲到第36页的时候才会出现,因为这个技术不是凭空产生的,它有着自己的演变进化的历史。我们要先弄清它从哪里来的?然后再说它能...

    WCF_Web2Web

    Client和Host均为Asp.net的WCF服务系统 环境vs.net2008 。 1:创建了一个WCF服务网站WCFserver ; 2:在这个站点里添加了一个"启用了解AJAX的WCF服务"的服务,名为ServiceWCF.svc ; 3:创建了另一个asp.net网站 WEB...

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

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

    wcf服务库 在 asp.net iis5 和 windows服务中的托管 ,最简单快速的方法

    wcf服务库 在 asp.net iis5 和 windows服务中的托管 ,最简单快速的方法

    WCF技术剖析pdf

    WCF技术剖析

    WCF技术专题_第五讲WCF通信模式

    常用的分布式技术有COM+、.NET远程技术(Remoting)、Web Service和微软消息队列服务,WCF技术将这些分布式技术整合为一个高效的API。常用的那些分布式技术只能解决项目开发中某个方面的问题,并且不同技术对平台...

    《ASP.NET.4 从入门到精通》张大威

    书中采用深受读者欢迎的step by step风格,指导读者通过具体的示例来熟悉和掌握asp.net4的重要特性,并通过练习的方式来进一步呈现和演示,有助于读者采用ajax、wcf服务、自定义控件和母版页等流行技术来创建出色的...

    20071121pm--微软经典案例系列课程(2):用ASP.NET和WCF构建高性能可扩展的企业级应用

    一个详细的StockTrader项目 .net下SOA应用的高性能及可扩展性

    WCF技术专题_第六讲WCF异步调用模式

    常用的分布式技术有COM+、.NET远程技术(Remoting)、Web Service和微软消息队列服务,WCF技术将这些分布式技术整合为一个高效的API。常用的那些分布式技术只能解决项目开发中某个方面的问题,并且不同技术对平台...

    MSDN_08年第一期

    本期MSDN杂志的主要内容有: ...• 非常 ASP.NET: 使用 ASP.NET 控件封装 Silverlight • { End Bracket }: 技术人员的激情 • 编者按: 新年新视角 • 工具箱: 高级单元测试、对象模拟、剖析应用程序及更多内容

Global site tag (gtag.js) - Google Analytics