示例代码下载地址: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();
        }
    }
}

运行程序:

完结

以上就是这几天看WCF相关资料的一个总结,希望还有时间看更多的东西吧

WCF备忘录一:服务端实例的生命周期的更多相关文章

  1. [WCF编程]8.服务实例的生命周期

    一.服务实例的生命周期概览 我们已经直到,通过显式调用Close方法或等待默认的超时时间到来,都可以释放服务实例.但是,在会话连接里,经常需要按一定顺序调用方法. 二.分步操作 会话契约的操作有时隐含 ...

  2. WCF心跳判断服务端及客户端是否掉线并实现重连接

    WCF心跳判断服务端及客户端是否掉线并实现重连接 本篇文章将通过一个实例实现对WCF中针对服务端以及客户端是否掉线进行判断:若掉线时服务器或客户端又在线时将实现自动重连:将通过WCF的双工知识以及相应 ...

  3. WCF客户端获取服务端异常[自定义异常]

    引言 经过不断的摸索,询问/调试,终于学会了关于WCF客户端与服务端之间异常的处理机制,在此来记录自己的成果,用于记录与分享给需要的伙伴们. 首先感谢[.NET技术群]里群主[轩]的大力帮助,如有需要 ...

  4. [ASP.NET Core 3框架揭秘] 依赖注入[8]:服务实例的生命周期

    生命周期决定了IServiceProvider对象采用怎样的方式提供和释放服务实例.虽然不同版本的依赖注入框架针对服务实例的生命周期管理采用了不同的实现,但总的来说原理还是类似的.在我们提供的依赖注入 ...

  5. Vue.js 1.x 和 2.x 实例的生命周期

    在Vue.js中,在实例化Vue之前,它们都是以HTML的文本形式存在文本编辑器中.当实例化后将经历创建.编译.销毁三个主要阶段. 以下是Vue.js 1.x  实例的生命周期图示: Vue.js 1 ...

  6. 前端MVC Vue2学习总结(二)——Vue的实例、生命周期与Vue脚手架(vue-cli)

    一.Vue的实例 1.1.创建一个 Vue 的实例 每个 Vue 应用都是通过 Vue 函数创建一个新的 Vue 实例开始的: var vm = new Vue({ // 选项 }) 虽然没有完全遵循 ...

  7. python 全栈开发,Day91(Vue实例的生命周期,组件间通信之中央事件总线bus,Vue Router,vue-cli 工具)

    昨日内容回顾 0. 组件注意事项!!! data属性必须是一个函数! 1. 注册全局组件 Vue.component('组件名',{ template: `` }) var app = new Vue ...

  8. Vue.js-07:第七章 - Vue 实例的生命周期

    一.前言  在之前的 Vue 学习中,我们在使用 Vue 时,都会创建一个 Vue 的实例,而每个 Vue 实例在被创建时都要经过一系列的初始化过程.例如,需要设置数据监听.编译模板.将实例挂载到 D ...

  9. Vue2.5笔记:Vue的实例与生命周期

    理解与认识 Vue 的实例是我们学习 Vue 非常重要的一步,也是非常必须的,因为实例是它的一个起点,也是它的一个入口,只有我们创建一个 Vue 实例之后,我们才行利用它进行一些列的操作. 首先 Vu ...

随机推荐

  1. 多个Img标签之间的间隙处理方法

    1.多个标签写在一行 <img src="/i/eg_tulip.jpg" alt="郁金香" height="100px"/> ...

  2. 前端学HTTP之实体和编码

    前面的话 每天都有各种媒体对象经由HTTP传送,如图像.文本.影片以及软件程序等.HTTP要确保它的报文被正确传送,识别.提取以及适当处理.为了实现这些目标,HTTP使用了完善的标签来描述承载内容的实 ...

  3. 【iOS10 SpeechRecognition】语音识别 现说现译的最佳实践

    首先想强调一下“语音识别”四个字字面意义上的需求:用户说话然后马上把用户说的话转成文字显示!,这才是开发者真正需要的功能. 做需求之前其实是先谷歌百度一下看有没有造好的轮子直接用,结果真的很呵呵,都是 ...

  4. 在Linux虚拟机下配置jdk的环境变量

    1.到Oracle公司的官网里下载好jdk,网址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133 ...

  5. linux常用查看硬件设备信息命令

    转载:http://blog.chinaunix.net/uid-26782198-id-3242120.html # uname -a               # 查看内核/操作系统/CPU信息 ...

  6. nginx启动报错:/usr/local/nginx/sbin/nginx: error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No such file or directory

    查看依赖库:

  7. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  8. CYQ.Data V5 从入门到放弃ORM系列:教程 - AppConfig、AppDebug类的使用

    1:AppConfig类的介绍: Public Static (Shared) Properties IsEnumToInt 是否使用表字段枚举转Int方式(默认为false). 设置为true时,可 ...

  9. 最新Linux部署.NET,Mono and DNX

    这几天一直在折腾在Linux下的ASP.NET 5,就下在看来在其它操作系统中ASP.NET 5或.NET应用,要想在完整的MS VM(CoreCLR)上运行还不远远达不到,应用的效果. 目前只能在M ...

  10. Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!

    随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...