WCF学习:Instance context model(实例模型) 与 Session(会话) 的关系
2009-09-17 15:36
621 查看
在WCF中对Session是默认支持的,但是和ASP.NET中的支持完全不同,说到Session,那么肯定有服务端(Service)和客户端(Client),客户端通过代理(Proxy)来访问服务端,所以Session的周期和Proxy的周期绑定。对分布式的程序而言,根据业务的要求,我们会有三种需求:
第一:服务端不用保存客户端的状态,每次客户端的访问都是独立的;
第二:服务端需要保持客户端的状态,每次客服端的请求会用到同一个Session;
第三:在多用户中共享同一个实例(其实这里类似ASP.NET中的Application,但完全不一样)。
下面我们就针对上述的三种要求,分享一下再WCF中的实现方式. 以及各种实现方式的优势和缺点。对上述三种使用场景,WCF已经提供了良好的支持,这就是Instancing Management。具体是实现方式是:Instance context model。可以这么说,Instance Context Mode决定着不同的Session表现。WCF中有三种 Instance Context Mode,他们分别是:
>> Per-Call:每次的客户端请求分配一个新的服务实例。 类似于Net Remoting的SingleCall模式, 在这种方式下,程序的扩展性是最强的,在事务编程与队列服务中优势更为明显。但是由于频繁地创建与销毁实例,会对性能造成一定的影响。当然网上的牛人,已经考虑到使用线程池的方式来减少频繁地创建与销毁实例(参考地址:http://www.cnblogs.com/artech/archive/2008/08/05/1260594.html)
>> PerSession: 服务端需要保持客户端的状态,为每次客户端连接分配一个服务实例,客户端的每次调用,会使用到同一个实例,如果实例销毁,客户端的调用会抛出异常。类似于Net Remoting的客户端激活模式;这是wcf的默认支持方式. 由于每个客户端都需要维护一个会话,需要占用较多的资源来保存服务会话状态。如果存在多个独立的客户端,则创建专门的服务实例的代价太大。
>> Singleton: 所有客户端而言,都只有一个服务实例,当服务端被host的时候,就会创建,有且仅有一个服务实例来响应客户端服务调用的请求,在多个客户端请求下,服务端只会处理一个客户端的请求,其他的排队等候处理。因此在系统的吞吐量、相应效率、系统服务性能上都存在严重的瓶颈
好处是,可以共享数据.
特别的强调两点:
第一:上述三种 Instance context model ,但是并不是所有的Binding都支持 Session ,对Per-Call和Singleton而言,binding影响不大。对PerSession,就必须使用特定的Binding, 才可以,否则最终指向的是PerCall,见下表:
第二:由于PerSession, 为每次客户端连接分配一个服务实例,会消耗服务器的资源,所以可以把PerSession和PerCall结合使用。在特定的条件下我们完全可以在客户端的Message中包括特定的用户性息来,请求PerCall,来代替每次请求PerSession。当然这是在特定的情况下。
下面来看具体的执行代码:
1、建立服务契约
[ServiceContract(Namespace = "http://www.cnblogs.com/wanqiming/")]
public interface IInstanceContextMode
{
//操作契约
[OperationContract]
void SayHello();
}
2、实现PerCall,PerSession,Single的服务类
#region PerCall
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class WCFServicePerCall : IInstanceContextMode, IDisposable
{
//服务实例计数
private int mCcount = 0;
//构造函数
public WCFServicePerCall()
{
Console.WriteLine("WCFServicePerCall Instance is Created ");
}
//实现接口定义的方法
public void SayHello()
{
mCcount++;
Console.WriteLine("WCFServicePerCall Instance Count is: {0} ", mCcount);
}
//实现接口定义的方法Dispose
public void Dispose()
{
Console.WriteLine("WCFServicePerCall Instance is disposed ");
}
}
#endregion
#region PerSession
//3.服务类.会话服务
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class WCFServicePerSession : IInstanceContextMode
{
//服务实例计数
private int mCcount = 0;
//构造函数
public WCFServicePerSession()
{
Console.WriteLine("WCFServicePerSession Instance is Created ");
}
//实现接口定义的方法
public void SayHello()
{
mCcount++;
Console.WriteLine("WCFServicePerSession Instance Count is: {0} ", mCcount);
}
//实现接口定义的方法Dispose
public void Dispose()
{
Console.WriteLine("WCFServicePerSession Instance is disposed ");
}
}
#endregion
#region Single
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class WCFServiceSingleTon : IInstanceContextMode
{
//服务实例计数
private int mCcount = 0;
//构造函数
public WCFServiceSingleTon()
{
Console.WriteLine("WCFServiceSingleTon Instance is Created ");
}
//实现接口定义的方法
public void SayHello()
{
mCcount++;
Console.WriteLine("WCFServiceSingleTon Instance Count is: {0} ", mCcount);
}
//实现接口定义的方法Dispose
public void Dispose()
{
Console.WriteLine("WCFServiceSingleTon Instance is disposed ");
}
}
#endregion
第三:服务端的配置文件
<behaviors>
<serviceBehaviors>
<behavior name="DefaultBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="100" maxConcurrentInstances="100" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Fish.ServiceImpl.WCFServicePerCall">
<endpoint address="" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<endpoint address="" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Fish/WCFServicePerCall/>
<add baseAddress="net.tcp://localhost:808/Fish/WCFServicePerCall"/>
</baseAddresses>
</host>
</service>
<service name="Fish.ServiceImpl.WCFServicePerSession">
<endpoint address="" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<endpoint address="" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:808/Fish/WCFServicePerSession"/>
<add baseAddress="http://localhost:8080/Fish/WCFServicePerSession/>
</baseAddresses>
</host>
</service>
<service behaviorConfiguration="DefaultBehavior" name="Fish.ServiceImpl.WCFServiceSingleTon">
<endpoint address="" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<endpoint address="" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:808/Fish/WCFServiceSingleTon"/>
<add baseAddress="http://localhost:8080/Fish/WCFServiceSingleTon/>
</baseAddresses>
</host>
</service>
第四:Host
class Program
{
static void Main(string[] args)
{
try
{
List<ServiceHost> hosts = new List<ServiceHost>();
hosts.Add(new ServiceHost(typeof(WCFServicePerCall))); //PerCall
hosts.Add(new ServiceHost(typeof(WCFServicePerSession))); //PerSession
hosts.Add(new ServiceHost(typeof(WCFServiceSingleTon))); //SingleTon
hosts.ForEach(host => host.Open());
Console.WriteLine("All services are started...");
Console.Read();
}
catch(Exception e)
{
Console.WriteLine("错误信息是:"+e.ToString());
}
}
}
第五:客户端执行代码
class Program
{
static void Main(string[] args)
{
PerCall();
PerSession();
Single();
Console.WriteLine(" ");
}
#region PerCall
private static void PerCall()
{
var perCall = new ChannelFactory<IInstanceContextMode>("tcpPerCall").CreateChannel();
perCall.SayHello();
perCall.SayHello();
perCall.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(perCall);
var tcpPerCall = new ChannelFactory<IInstanceContextMode>("tcpPerCall").CreateChannel();
tcpPerCall.SayHello();
tcpPerCall.SayHello();
tcpPerCall.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(tcpPerCall);
}
#endregion
#region PerSession
private static void PerSession()
{
var perSession = new ChannelFactory<IInstanceContextMode>("basicHttpPerSession").CreateChannel();
perSession.SayHello();
perSession.SayHello();
perSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(perSession);
var tcpPerSession = new ChannelFactory<IInstanceContextMode>("tcpPerSession").CreateChannel();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(tcpPerSession);
}
#endregion
#region Single
private static void Single()
{
var perSession = new ChannelFactory<IInstanceContextMode>("basicHttpSingleTon").CreateChannel();
perSession.SayHello();
perSession.SayHello();
perSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(perSession);
var tcpPerSession = new ChannelFactory<IInstanceContextMode>("tcpSingleTon").CreateChannel();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(tcpPerSession);
}
#endregion
}
第六:客户端配置文件
<client>
<endpoint name="httpPerCall" address="http://localhost:8080/Fish/WCFServicePerCall" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="tcpPerCall" address="net.tcp://localhost:808/Fish/WCFServicePerCall" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="basicHttpPerSession" address="http://localhost:8080/Fish/WCFServicePerSession" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="tcpPerSession" address="net.tcp://localhost:808/Fish/WCFServicePerSession" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="basicHttpSingleTon" address="http://localhost:8080/Fish/WCFServiceSingleTon" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="tcpSingleTon" address="net.tcp://localhost:808/Fish/WCFServiceSingleTon" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
</client> 执行的结果如下:
代码下载:/Files/wanqiming/Fish.rar
第一:服务端不用保存客户端的状态,每次客户端的访问都是独立的;
第二:服务端需要保持客户端的状态,每次客服端的请求会用到同一个Session;
第三:在多用户中共享同一个实例(其实这里类似ASP.NET中的Application,但完全不一样)。
下面我们就针对上述的三种要求,分享一下再WCF中的实现方式. 以及各种实现方式的优势和缺点。对上述三种使用场景,WCF已经提供了良好的支持,这就是Instancing Management。具体是实现方式是:Instance context model。可以这么说,Instance Context Mode决定着不同的Session表现。WCF中有三种 Instance Context Mode,他们分别是:
>> Per-Call:每次的客户端请求分配一个新的服务实例。 类似于Net Remoting的SingleCall模式, 在这种方式下,程序的扩展性是最强的,在事务编程与队列服务中优势更为明显。但是由于频繁地创建与销毁实例,会对性能造成一定的影响。当然网上的牛人,已经考虑到使用线程池的方式来减少频繁地创建与销毁实例(参考地址:http://www.cnblogs.com/artech/archive/2008/08/05/1260594.html)
>> PerSession: 服务端需要保持客户端的状态,为每次客户端连接分配一个服务实例,客户端的每次调用,会使用到同一个实例,如果实例销毁,客户端的调用会抛出异常。类似于Net Remoting的客户端激活模式;这是wcf的默认支持方式. 由于每个客户端都需要维护一个会话,需要占用较多的资源来保存服务会话状态。如果存在多个独立的客户端,则创建专门的服务实例的代价太大。
>> Singleton: 所有客户端而言,都只有一个服务实例,当服务端被host的时候,就会创建,有且仅有一个服务实例来响应客户端服务调用的请求,在多个客户端请求下,服务端只会处理一个客户端的请求,其他的排队等候处理。因此在系统的吞吐量、相应效率、系统服务性能上都存在严重的瓶颈
好处是,可以共享数据.
特别的强调两点:
第一:上述三种 Instance context model ,但是并不是所有的Binding都支持 Session ,对Per-Call和Singleton而言,binding影响不大。对PerSession,就必须使用特定的Binding, 才可以,否则最终指向的是PerCall,见下表:
Binding | Session mode | Context mode | Async Dispose() | Instance mode |
---|---|---|---|---|
Basic | Allowed/NotAllowed | PerCall/PerSession | Yes | PerCall |
TCP, IPC | Allowed/Required | PerCall | No | PerCall |
TCP, IPC | Allowed/Required | PerSession | Yes | PerSession |
WS (no security, no reliability) | NotAllowed/Allowed | PerCall/PerSession | Yes | PerCall |
WS (with security or reliability) | Allowed/Required | PerSession | Yes | PerSession |
WS (with security or reliability) | NotAllowed | PerCall/PerSession | Yes | PerCall |
下面来看具体的执行代码:
1、建立服务契约
[ServiceContract(Namespace = "http://www.cnblogs.com/wanqiming/")]
public interface IInstanceContextMode
{
//操作契约
[OperationContract]
void SayHello();
}
2、实现PerCall,PerSession,Single的服务类
#region PerCall
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class WCFServicePerCall : IInstanceContextMode, IDisposable
{
//服务实例计数
private int mCcount = 0;
//构造函数
public WCFServicePerCall()
{
Console.WriteLine("WCFServicePerCall Instance is Created ");
}
//实现接口定义的方法
public void SayHello()
{
mCcount++;
Console.WriteLine("WCFServicePerCall Instance Count is: {0} ", mCcount);
}
//实现接口定义的方法Dispose
public void Dispose()
{
Console.WriteLine("WCFServicePerCall Instance is disposed ");
}
}
#endregion
#region PerSession
//3.服务类.会话服务
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class WCFServicePerSession : IInstanceContextMode
{
//服务实例计数
private int mCcount = 0;
//构造函数
public WCFServicePerSession()
{
Console.WriteLine("WCFServicePerSession Instance is Created ");
}
//实现接口定义的方法
public void SayHello()
{
mCcount++;
Console.WriteLine("WCFServicePerSession Instance Count is: {0} ", mCcount);
}
//实现接口定义的方法Dispose
public void Dispose()
{
Console.WriteLine("WCFServicePerSession Instance is disposed ");
}
}
#endregion
#region Single
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class WCFServiceSingleTon : IInstanceContextMode
{
//服务实例计数
private int mCcount = 0;
//构造函数
public WCFServiceSingleTon()
{
Console.WriteLine("WCFServiceSingleTon Instance is Created ");
}
//实现接口定义的方法
public void SayHello()
{
mCcount++;
Console.WriteLine("WCFServiceSingleTon Instance Count is: {0} ", mCcount);
}
//实现接口定义的方法Dispose
public void Dispose()
{
Console.WriteLine("WCFServiceSingleTon Instance is disposed ");
}
}
#endregion
第三:服务端的配置文件
<behaviors>
<serviceBehaviors>
<behavior name="DefaultBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="100" maxConcurrentInstances="100" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Fish.ServiceImpl.WCFServicePerCall">
<endpoint address="" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<endpoint address="" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Fish/WCFServicePerCall/>
<add baseAddress="net.tcp://localhost:808/Fish/WCFServicePerCall"/>
</baseAddresses>
</host>
</service>
<service name="Fish.ServiceImpl.WCFServicePerSession">
<endpoint address="" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<endpoint address="" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:808/Fish/WCFServicePerSession"/>
<add baseAddress="http://localhost:8080/Fish/WCFServicePerSession/>
</baseAddresses>
</host>
</service>
<service behaviorConfiguration="DefaultBehavior" name="Fish.ServiceImpl.WCFServiceSingleTon">
<endpoint address="" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<endpoint address="" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:808/Fish/WCFServiceSingleTon"/>
<add baseAddress="http://localhost:8080/Fish/WCFServiceSingleTon/>
</baseAddresses>
</host>
</service>
第四:Host
class Program
{
static void Main(string[] args)
{
try
{
List<ServiceHost> hosts = new List<ServiceHost>();
hosts.Add(new ServiceHost(typeof(WCFServicePerCall))); //PerCall
hosts.Add(new ServiceHost(typeof(WCFServicePerSession))); //PerSession
hosts.Add(new ServiceHost(typeof(WCFServiceSingleTon))); //SingleTon
hosts.ForEach(host => host.Open());
Console.WriteLine("All services are started...");
Console.Read();
}
catch(Exception e)
{
Console.WriteLine("错误信息是:"+e.ToString());
}
}
}
第五:客户端执行代码
class Program
{
static void Main(string[] args)
{
PerCall();
PerSession();
Single();
Console.WriteLine(" ");
}
#region PerCall
private static void PerCall()
{
var perCall = new ChannelFactory<IInstanceContextMode>("tcpPerCall").CreateChannel();
perCall.SayHello();
perCall.SayHello();
perCall.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(perCall);
var tcpPerCall = new ChannelFactory<IInstanceContextMode>("tcpPerCall").CreateChannel();
tcpPerCall.SayHello();
tcpPerCall.SayHello();
tcpPerCall.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(tcpPerCall);
}
#endregion
#region PerSession
private static void PerSession()
{
var perSession = new ChannelFactory<IInstanceContextMode>("basicHttpPerSession").CreateChannel();
perSession.SayHello();
perSession.SayHello();
perSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(perSession);
var tcpPerSession = new ChannelFactory<IInstanceContextMode>("tcpPerSession").CreateChannel();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(tcpPerSession);
}
#endregion
#region Single
private static void Single()
{
var perSession = new ChannelFactory<IInstanceContextMode>("basicHttpSingleTon").CreateChannel();
perSession.SayHello();
perSession.SayHello();
perSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(perSession);
var tcpPerSession = new ChannelFactory<IInstanceContextMode>("tcpSingleTon").CreateChannel();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(tcpPerSession);
}
#endregion
}
第六:客户端配置文件
<client>
<endpoint name="httpPerCall" address="http://localhost:8080/Fish/WCFServicePerCall" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="tcpPerCall" address="net.tcp://localhost:808/Fish/WCFServicePerCall" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="basicHttpPerSession" address="http://localhost:8080/Fish/WCFServicePerSession" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="tcpPerSession" address="net.tcp://localhost:808/Fish/WCFServicePerSession" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="basicHttpSingleTon" address="http://localhost:8080/Fish/WCFServiceSingleTon" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="tcpSingleTon" address="net.tcp://localhost:808/Fish/WCFServiceSingleTon" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
</client> 执行的结果如下:
代码下载:/Files/wanqiming/Fish.rar
相关文章推荐
- WCF学习笔记之实例与会话(Instance And Session)
- WCF中实例模式(InstanceContextMode)与会话模式(SessionMode)
- 化零为整WCF(10) - 实例模型(InstanceContextMode)
- WCF会话(SESSION)与实例(INSTANCE)管理
- WCF会话(Session)与实例(Instance)管理
- mysql中数据库database、实例instance、会话session的关系
- WCF中实例模式(InstanceContextMode)与会话模式(SessionMode)
- 化零为整WCF(10) - 实例模型(InstanceContextMode)
- RailsCasts中文版,#13 Dangers of Model in Session 不要在会话中缓存模型实例
- 化零为整WCF(10) - 实例模型(InstanceContextMode)
- 【转载】WCF中实例模式(InstanceContextMode)与会话模式(SessionMode)
- asp.net底层架构学习笔记(IIS5/6/7处理模型,HttpRuntime,HttpContext,HttpApplication,HttpModel,HttpHandler...)
- Python ORM框架SQLAlchemy学习笔记之映射类使用实例和Session会话介绍
- JavaWeb学习之转发和重定向、会话技术:cookie、session、验证码实例、URLConnection使用(下载网页)(4)
- EF(Entity Framework)发生错误”正在创建模型,此时不可使用上下文“的解决办法。 正在创建模型,此时不可使用上下文。如果在 OnModelCreating 方法内使用上下文或如果多个线程同时访问同一上下文实例,可能引发此异常。请注意不保证 DbContext 的实例成员和相关类是线程安全的。 临时解决了这个问题,在Context的构造函数中,禁用了自动初始化:
- Django学习07---model模型以及关系模型
- 【踩坑(Running)填坑(ZSSURE)】:WCF学习之InstanceContextMode与ConcurrencyMode
- WCF实例上下文模式与并发模式对性能的影响 转载自:http://log.medcl.net/item/2010/03/wcf-instance-context-mode-and-the-performance-impact-of-conc
- WCF实例上下文以及会话学习
- 关于WCF的InstanceContextMode,与会话相关