示例代码下载地址:WCFDemo1Day

概述

客户端向WCF服务发出请求后,服务端会实例化一个Service对象(实现了契约接口的对象)用来处理请求,实例化Service对象以及维护其生命周期的方式在WCF中共有三种不同的类型,分别是:

  • Per-Call
  • Per-Session
  • Single

程序中通过设置ServiceBehavior特性来指定,如下:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class CommService : ICommContract
{
}

这是枚举InstanceContextMode的内容:

public enum InstanceContextMode
{
PerSession = 0,
PerCall = 1,
Single = 2,
}

Per-Call

每次调用服务端服务端方法,服务端都会实例化一个对象来处理请求,为观察结果,现编写如下代码:

服务类:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class CommService : ICommContract
{
public CommService()
{
Console.WriteLine("构造函数被执行");
} public int Add(int a, int b)
{
Console.WriteLine("Add被调用,Thread:" + Thread.CurrentThread.ManagedThreadId + " fromPool:" + Thread.CurrentThread.IsThreadPoolThread); return a + b;
} public void Dispose()
{
Console.WriteLine("对象销毁");
Console.WriteLine("_____________________________");
} public void SendStr(string str)
{
Console.WriteLine("SendStr被调用,Thread:" + Thread.CurrentThread.ManagedThreadId + " fromPool:" + Thread.CurrentThread.IsThreadPoolThread);
}
}

如果服务类实现了接口IDisposable,当服务类被销毁时会回调Dispose方法,可以在Dispose方法中写一些WriteLine语句以观察对象的生命周期。

客户端代码:

class Program
{
static void Main(string[] args)
{
CommService.CommContractClient client = new CommService.CommContractClient(); client.SendStr("hello");
client.SendStr("hello");
client.SendStr("hello"); client.Close();
}
}

运行效果:

Per-Session

InstanceContextMode被设置为PerSession后,同一个客户端多次调用一个远程Web服务方法时,服务端只会实例化一次,修改上面的服务端代码第一行如下:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]

再看运行效果:

上面的实例代码所使用的绑定模式为WSHttpBinding,如果使用BasicHttpBinding的话,即使是指定了InstanceContextModePerSession服务端也不会保存会话,现将支持Per-Session的绑定方式列举如下:

  • WSXXXBinding(with Message security or reliability)
  • NetTcpXXXBinding
  • NetXXXPipeBinding

后两个容易理解,第一个括号里什么什么玩意儿,请看宿主代码:

 class Program
{
static void Main(string[] args)
{
Uri baseURI = new Uri("http://localhost:8000/Services");
ServiceHost host = new ServiceHost(typeof(CommService), baseURI); try
{
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.None;
host.AddServiceEndpoint(typeof(ICommContract), binding, "CommonService"); ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetUrl = new Uri("http://localhost:8080/Services");
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add(smb); host.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine(); host.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("An exception occurred: {0}", ce.Message);
host.Abort();
}
}
}

binding.Security.Mode默认为Message,现在把它改成None再运行程序:

哈,虽然InstanceContextMode设置为了Per-Session,实际上还是Per-Call,这部分内容和安全性有关,希望我有时间以后会写到吧,今天暂时不去研究。

除了绑定方式,还有一个地方也影响到了Per-Session是否起作用,它是契约接口特性ServiceContract的属性SessionMode,该枚举内容如下:

public enum SessionMode
{
Allowed = 0,
Required = 1,
NotAllowed = 2,
}

SessionMode属性默认是Allowed,如果设置为Required表示必须启用会话模式,NotAllowed表示必须不能启动会话模式,Allowed表示无所谓。谁有兴趣可以一一尝试。现将契约接口的特性改成如下:

[ServiceContract(Namespace = "zzy0471.cnblogs.com.CommService", SessionMode = SessionMode.NotAllowed)]
public interface ICommContract : IDisposable
{
[OperationContract()]
int Add(int a, int b); [OperationContract()]
void SendStr(String str);
}

再运行程序:

虽然InstanceContextMode设置为了Per-Session,实际上还是Per-Call

此外,还有一个需要注意的地方,如果在方法契约特性中设置属性IsTerminatingtrue,如下图

[OperationContract(IsTerminating = true)]
void SendStr(String str);

运行服务端会导致运行时错误,IsTerminating设置为了truePer-Session模式相矛盾,IsTerminating的意思是:“获取或设置一个值,该值指示服务操作在发送答复消息(如果存在)后,是否会导致服务器关闭会话”

Per-Single

InstanceContextMode被设置为PerSingle后,所有的客户端请求都只有一个服务端实例对象来处理,服务启动时对象创建,服务关闭时对象销毁。现修改InstanceContextMode特性如下:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class CommService : ICommContract
{
public CommService()
{
Console.WriteLine("构造函数被执行");
} public int Add(int a, int b)
{
Console.WriteLine("Add被调用,Thread:" + Thread.CurrentThread.ManagedThreadId + " fromPool:" + Thread.CurrentThread.IsThreadPoolThread); return a + b;
} public void Dispose()
{
Console.WriteLine("对象销毁");
Console.WriteLine("_____________________________");
} public void SendStr(string str)
{
Console.WriteLine("SendStr被调用,Thread:" + Thread.CurrentThread.ManagedThreadId + " fromPool:" + Thread.CurrentThread.IsThreadPoolThread);
}
}

为了方便观察,修改客户端代码,以模拟多个客户端:

class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 3; i++)
{
CommService.CommContractClient client = new CommService.CommContractClient(); client.SendStr("hello");
client.SendStr("hello");
client.SendStr("hello"); client.Close();
}
}
}

运行程序:

Learning WCF:Life Cycle of Service instance的更多相关文章

  1. WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇]

    原文:WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇] 在[第2篇]中,我们深入剖析了单调(PerCall)模式下WCF对服务实例生命周期的控制,现在我们来 ...

  2. Learning WCF Chapter1 Creating a New Service from Scratch

    You’re about to be introduced to the WCF service. This lab isn’t your typical “Hello World”—it’s “He ...

  3. Learning WCF:Fault Handling

    There are two types of Execptions which can be throwed from the WCF service. They are Application ex ...

  4. Learning WCF:A Simple Demo

    This is a very simple demo which can help you create a wcf applition quickly. Create a Solution Open ...

  5. Learning WCF Chapter1 Hosting a Service in IIS

    How messages reach a service endpoint is a matter of protocols and hosting. IIS can host services ov ...

  6. Learning WCF Chapter1 Generating a Service and Client Proxy

    In the previous lab,you created a service and client from scratch without leveraging the tools avail ...

  7. Learning WCF Chapter1 Exposing Multiple Service Endpoints

    So far in this chapter,I have shown you different ways to create services,how to expose a service en ...

  8. WCF 的 Service Instance模式和并发处理

    WCF 的 Service Instance(实例)有三种模式 PerCall:每一次调用都创建一个实例,每一次调用结束后回收实例.此模式完全无状态. PerSession:调用者打开Channel时 ...

  9. WCF:为 SharePoint 2010 Business Connectivity Services 构建 WCF Web 服务(第 1 部分,共 4 部分)

    转:http://msdn.microsoft.com/zh-cn/library/gg318615.aspx 摘要:通过此系列文章(共四部分)了解如何在 Microsoft SharePoint F ...

随机推荐

  1. JS截取URL地址参数

    var url = window.location.search; 截取?r= 后面的参数var url = window.location.href;var urlss= urlssplit('co ...

  2. django session 的简单操作

    #!SESSION_SAVE_EVERY_REQUEST = True 设置根据最后一次操作设置登录超时时间#!SESSION_EXPIRE_AT_BROWSER_CLOSE = True 设置是否关 ...

  3. openvpn通过ldap或ad统一认证解决方案思路分享

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://oldboy.blog.51cto.com/2561410/986933 缘起:成 ...

  4. leetcode23

    public class Solution { public ListNode MergeKLists(ListNode[] lists) { var ary = new List<int> ...

  5. 剑指offer例题——二进制中1的个数

    题目:输入一个整数,输出该二进制表示中1的个数.其中负数用补码表示. 首先明确补码的定义: 原码 反码 补码 将最高位作为符号位(0表示正,1表示负), 其它数字位表达数值本身的绝对值的数字表示方式 ...

  6. 《Android Studio开发实战 从零基础到App上线》资源下载和内容勘误

    转载于:https://blog.csdn.net/aqi00/article/details/73065392 资源下载 下面是<Android Studio开发实战 从零基础到App上线&g ...

  7. MFC笔记10

    1. CDC MemDC1; MemDC1.SetBkMode(OPAQUE); 背景模式,VC6下面有三种:/* Background Modes */#define TRANSPARENT 1// ...

  8. Java JDK 在Windows 10中配置环境变量

    首先,去Oracle官方网站下载Java JDK https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-213 ...

  9. Django REST framework的分页

    DRF分页组件 为什么要使用分页 我们数据表中可能会有成千上万条数据,当我们访问某张表的所有数据时,我们不太可能需要一次把所有的数据都展示出来,因为数据量很大,对服务端的内存压力比较大还有就是网络传输 ...

  10. MYSQL 时间类型

    常见四种:DATE, TIME, DATETIME, TIMESTAMP DATE: 只表示年月日,YYYY-MM-DD TIME: 只表示时分秒,HH-mm-SS DATETIME: DATE和TI ...