在[第1篇]中,我们介绍了WCF关于实例管理一些基本的知识点,包括InstanceContext、InstanceContextMode、已经如何通过ServiceBehaviorAttribute应用不同的实例上下文模式给不同的服务。在[第1篇]中,对WCF采用的三种不同实例上下文模式进行了简单的比较,本篇的重点方法对单调(PerCall)模式为进行详细介绍。
在单调(Per-Call)实例上下文模式下,WCF总是创建一个新的服务实例上下文处理接收到的每一个服务调用请求,并在服务操作执行结束后,回收服务上下文和服务实例。换句话说,单调服务实例上下文模式使服务实例上下文的生命周期与服务调用本身绑定。我们首先来介绍单调模式下服务实例上下文具体有怎样的生命周期。
一、 单调模式下的服务实例上下文提供机制
对于单调模式,服务实例的生命周期大体上可以看成服务操作执行的生命周期。服务实例在服务操作执行前被创建,在操作完成之后被回收。下面的列表揭示了在单调模式下,对于每一次服务调用请求,WCF的整个服务实例激活过程:
- WCF服务端接收到来自客户端的服务调用请求;
- 通过实例上下文提供者(InstanceContextProvider)对象试图获取现有服务实例的实例上下文,对于单调模式,返回的实例上下文永远为空;
- 如果获取实例上下文为空,则通过实例提供者(IntanceProvider)创建服务实例,封装到新创建的实例上下文中;
- 通过InstanceContext的GetServiceInstance方法获取服务实例对象,借助操作选择器(OperationSelector)选择出相应的服务操作,最后通过操作执行器(OperationInvoker)对象执行相应的操作方法;
- 操作方法执行完毕后,关闭被卸载InstanceContext对象。在此过程中,会调用InstanceProvider对象释放服务实例,如果服务类型实现了接口IDisposable,则会调用Disposable方法;
- 服务实例成为垃圾对象,等待GC回收。
对于上述列表中提到的InstanceContextProvider、InstanceProvider等重要的对象,以及相关的实现机制,将在本系列后续的部分进行单独讲解。为了加深读者的理解,这里通过一个简单的例子来演示在单调模式下服务实例的整个激活流程。
二、 实例演示:单调模式下服务实例的生命周期
本案例依然沿用典型的4层结构和计算服务的场景,下面是服务契约和具体服务实现的定义。在CalculatorService类型上,通过ServiceBehaviorAttribute特性将实例上下文模式设为单调(Per-Call)模式。为了演示服务实例的创建、释放和回收,我们分别定义了无参构造函数,终止化器(Finalizer)以及实现的接口IDisposable,并在所有的方法中输出相应的指示性文字,以便更容易地观测到它们执行的先后顺序。
1: using System.ServiceModel;
<!--CRLF-->
2: namespace Artech.WcfServices.Contracts
<!--CRLF-->
3: {
<!--CRLF-->
4: [ServiceContract(Namespace="http://www.artech.com/")]
<!--CRLF-->
5: public interface ICalculator
<!--CRLF-->
6: {
<!--CRLF-->
7: [OperationContract]
<!--CRLF-->
8: double Add(double x, double y);
<!--CRLF-->
9: }
<!--CRLF-->
10: }
<!--CRLF-->
1: using System;
<!--CRLF-->
2: using System.ServiceModel;
<!--CRLF-->
3: using Artech.WcfServices.Contracts;
<!--CRLF-->
4: namespace Artech.WcfServices.Services
<!--CRLF-->
5: {
<!--CRLF-->
6: [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
<!--CRLF-->
7: public class CalculatorService : ICalculator, IDisposable
<!--CRLF-->
8: {
<!--CRLF-->
9: public CalculatorService()
<!--CRLF-->
10: {
<!--CRLF-->
11: Console.WriteLine("Service object is instantiated.");
<!--CRLF-->
12: }
<!--CRLF-->
13: ~CalculatorService()
<!--CRLF-->
14: {
<!--CRLF-->
15: Console.WriteLine("Service object is finalized.");
<!--CRLF-->
16: }
<!--CRLF-->
17:
<!--CRLF-->
18: public void Dispose()
<!--CRLF-->
19: {
<!--CRLF-->
20: Console.WriteLine("Service object is disposed.");
<!--CRLF-->
21: }
<!--CRLF-->
22: public double Add(double x, double y)
<!--CRLF-->
23: {
<!--CRLF-->
24: Console.WriteLine("Operation method is invoked.");
<!--CRLF-->
25: return x + y;
<!--CRLF-->
26: }
<!--CRLF-->
27: }
<!--CRLF-->
28: }
<!--CRLF-->
为了演示GC对服务实例的回收,在进行服务寄宿的时候,通过System.Threading.Timer使GC每隔10毫秒强制执行一次垃圾回收。
1: using System;
<!--CRLF-->
2: using System.ServiceModel;
<!--CRLF-->
3: using System.Threading;
<!--CRLF-->
4: using Artech.WcfServices.Services;
<!--CRLF-->
5: namespace Artech.WcfServices.Hosting
<!--CRLF-->
6: {
<!--CRLF-->
7: public class Program
<!--CRLF-->
8: {
<!--CRLF-->
9: private static Timer GCScheduler;
<!--CRLF-->
10:
<!--CRLF-->
11: static void Main(string[] args)
<!--CRLF-->
12: {
<!--CRLF-->
13: GCScheduler = new Timer(
<!--CRLF-->
14: delegate
<!--CRLF-->
15: {
<!--CRLF-->
16: GC.Collect();
<!--CRLF-->
17: }, null, 0, 100);
<!--CRLF-->
18: using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
<!--CRLF-->
19: {
<!--CRLF-->
20: serviceHost.Open();
<!--CRLF-->
21: Console.Read();
<!--CRLF-->
22: }
<!--CRLF-->
23: }
<!--CRLF-->
24: }
<!--CRLF-->
25: }
<!--CRLF-->
通过一个控制台应用程序对服务进行成功寄宿后,客户端通过下面的代码,使用相同的服务代理对象进行两次服务调用。
1: using System;
<!--CRLF-->
2: using System.ServiceModel;
<!--CRLF-->
3: using Artech.WcfServices.Contracts;
<!--CRLF-->
4: namespace Artech.WcfServices.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 calculator = channelFactory.CreateChannel();
<!--CRLF-->
13: Console.WriteLine("x + y = {2} when x = {0} and y = {1}", 1, 2, calculator.Add(1, 2));
<!--CRLF-->
14: Console.WriteLine("x + y = {2} when x = {0} and y = {1}: {3}", 1, 2, calculator.Add(1, 2));
<!--CRLF-->
15: }
<!--CRLF-->
16: }
<!--CRLF-->
17: }
<!--CRLF-->
18: }
<!--CRLF-->
从运行后服务端的输出可以看出,对于两次服务调用请求,服务端先后创建了两个服务实例,在操作方法成功执行后,Dispose方法得以执行。而终止化器(Finalizer)是被GC在后台执行的,所以执行的时机不能确定。不过有一点可以从中得到证实:当服务操作执行时,服务实例变成了“垃圾”对象,并可以被GC回收以腾出占据的内存空间。
Service object is instantiated.
<!--CRLF-->
Operation method is invoked.
<!--CRLF-->
Service object is disposed.
<!--CRLF-->
Service object is instantiated.
<!--CRLF-->
Operation method is invoked.
<!--CRLF-->
Service object is disposed.
<!--CRLF-->
Service object is finalized.
<!--CRLF-->
Service object is finalized.
<!--CRLF-->
三、 服务实例上下文的释放
如果服务实例须要引用一些非托管资源,比如数据库连接、文件句柄等,须要及时将其释放。在这种情况下,我们可以通过实现IDisposable接口,在Dispose方法中进行相应的资源回收工作。在单调实例上下文模式下,当服务操作执行时,Dispose方法会自动被执行,这一点已经通过上面的案例演示得到证实。
对于实现了IDisposable接口的Dispose方法,有一点值得注意的是:该方法是以与操作方法同步形式执行的。也就是说,服务操作和Dispose方法在相同的线程中执行。认识这一点很重要,因为无论采用怎样的实例模式,在支持会话(Session)的情况下如果服务请求来自于同一个服务代理,服务操作都会在一个线程下执行。对于单调模式就会出现这样的问题:由于Dispose方法同步执行的特性,如果该方法是一个比较耗时的操作,那么来自于同一个服务代理的服务后续调用请求将不能得到及时执行。WCF只能在上一个服务实例被成功释放之后,才能处理来自相同服务代理的下一个服务调用请求。为了让读者体会到同步方式释放服务实例在应用中的影响,并证明同步释放服务实例的现象,我们对上面的案例略加改动。
在CalculatorService中,通过线程休眠的方式模拟耗时的服务实例释放操作(5秒)。在Dispose和Add方法中,除了输出具体操作名称之外,还会输出当前的线程ID和执行的开始时间,代码如下所示。
1: [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
<!--CRLF-->
2: public class CalculatorService : ICalculator, IDisposable
<!--CRLF-->
3: {
<!--CRLF-->
4: public void Dispose()
<!--CRLF-->
5: {
<!--CRLF-->
6: Console.WriteLine("Time: {0}; Thread ID: {1}; Service object is disposed.", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
<!--CRLF-->
7: Thread.Sleep(5000);
<!--CRLF-->
8: }
<!--CRLF-->
9: public double Add(double x, double y)
<!--CRLF-->
10: {
<!--CRLF-->
11: Console.WriteLine("Time: {0}; Thread ID: {1}; Operation method is invoked.", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
<!--CRLF-->
12: return x + y;
<!--CRLF-->
13: }
<!--CRLF-->
border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-righ
分享到:
相关推荐
蒋金楠老师的wcf教程,个人看了,觉得写的很不错,对刚入门和深入了解wcf都适用,有需要的同学可下载学习
WCF技术剖析
wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例wcf经典实例
WCF技术剖析(卷1),是一本非常专业的不错的WCF技术类的书籍。
wcf 服务寄宿到windows service上
《WCF技术剖析》从WCF的终结点谈起,对终结点的三要素进行了全面而深入的介绍,帮助读者了解地址、绑定和契约的本质。 通过本书对序列化的深入讲解,读者可了解WCF进行操作方法调用与消息之间转化的本质;深入剖析...
wcf实用例子包含2中方式,分别是iis版本和windows服务版本,很实用
wcf实例化-单调服务模式,言简意赅,很容易理解。就是现在积分没发控制,不然1分即可。很简单的代码
WCF 22个实例2 wcf 值得收藏,好资源
JS调用WCF服务实例(WCF服务宿主到控制台),解决Js跨域调用问题 源码实例 wcf宿主到控制台上,并内置js调用服务的源码
常用的分布式技术有COM+、.NET远程技术(Remoting)、Web Service和微软消息队列服务,WCF技术将这些分布式技术整合为一个高效的API。常用的那些分布式技术只能解决项目开发中某个方面的问题,并且不同技术对平台...
常用的分布式技术有COM+、.NET远程技术(Remoting)、Web Service和微软消息队列服务,WCF技术将这些分布式技术整合为一个高效的API。常用的那些分布式技术只能解决项目开发中某个方面的问题,并且不同技术对平台...
《WCF全面解析(套装上下册)》由蒋金楠所著,是作者多年潜心研究WCF技术的心血之作,也是这些年来从事WCF开发的经验总结。书如其名,此书涵盖了WCF几乎所有的知识点,并对其底层框架进行了“庖丁解牛”式的剖析,力求...
1:创建第一个WCF服务 2: 使用IIS发布WCF服务 3:自运行WCF服务 4:使用Windows服务发布WCF服务 5:创建WCF客户端程序
《WCF编程(第2版)》被誉为WCF的最佳开发指南,提供了深入的技术剖析,而非死板的文档化描述,以帮助开发者掌握WCF的必备知识与技能,并构建可维护的、可扩展的以及可重用的WCF应用程序。 作为微软授予的“软件英杰”...
常用的分布式技术有COM+、.NET远程技术(Remoting)、Web Service和微软消息队列服务,WCF技术将这些分布式技术整合为一个高效的API。常用的那些分布式技术只能解决项目开发中某个方面的问题,并且不同技术对平台...
WCF实例管理的概述,WCF服务实例激活类型三种方式概述和单例服务的完整代码。
什么是 WCF Windows 通信基础( ...许多有用的功能, 包括托管( Hosting)、 服务实例管理( Service Instance Management)、 异步调用、可靠性、事务管理、离线队列调用( Disconnected Queued Call)以及安全
WCF传输使用实例WCF传输使用实例WCF传输使用实例
WCF服务,配置可同时支持web调用和WCF调用,可以用于C#程序服务访问,也支持java等程序访问。java通过web调用,C#可以通过wcf访问。