示例代码下载地址: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. js:给定两个数组,如何判断他们的相对应下标的元素类型是一样的

    题目: 给Array对象原型上添加一个sameStructureAs方法,该方法接收一个任意类型的参数,要求返回当前数组与传入参数数组(假定是)相对应下标的元素类型是否一致. 假设已经写好了Array ...

  2. golang语言构造函数

    1.构造函数定义 构造函数 ,是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.特别的一个类可以有多个构造函数 ,可根据其参数个 ...

  3. winform 窗体圆角设计

    网上看到的很多winform窗体圆角设计代码都比较累赘,这里分享一个少量代码就可以实现的圆角.主要运用了System.Drawing.Drawing2D. 效果图 代码如下. private void ...

  4. python中IndentationError: expected an indented block错误的解决方法

    IndentationError: expected an indented block 翻译为IndentationError:预期的缩进块 解决方法:有冒号的下一行要缩进,该缩进就缩进

  5. Zabbix 漏洞分析

    之前看到Zabbix 出现SQL注入漏洞,自己来尝试分析. PS:我没找到3.0.3版本的 Zabbix ,暂用的是zabbix 2.2.0版本,如果有问题,请大牛指点. 0x00 Zabbix简介 ...

  6. Java—恶心的java.lang.NumberFormatException解决

    项目中要把十六进制字符串转化为十进制, 用到了到了Integer.parseInt(str1.trim(), 16):这个是不是后抛出java.lang.NumberFormatException异常 ...

  7. 发布APP到app store

    好久好久没写博客了,主要是 都在学习新东西,忙不赢啊. 近段时间在用AC平台学习开发移动APP, 今天开始发布应用. 在ac云控制台编译成ipa后,使用apple提供的Application Load ...

  8. i++、++i 、i--、--i

    总结: i++ 先用后加, ++i先加后用: i--先用后减, --i先减后用: //int i = 1; //Console.WriteLine(i);//1 //Console.WriteLine ...

  9. hbase协处理器编码实例

    Observer协处理器通常在一个特定的事件(诸如Get或Put)之前或之后发生,相当于RDBMS中的触发器.Endpoint协处理器则类似于RDBMS中的存储过程,因为它可以让你在RegionSer ...

  10. Linux的学习笔记

    Linux,1991年,系统安全,良好的可移植性,多用户,多任务,良好的兼容性,良好的用户界面, 主流的是RedHat或者CentOS, CentOS 设置的网关 192.168.2.2 Window ...