WCF的实例java工厂模式实例PerSession怎么使用

一、理解Session
1.Session的作用:保留Client和Service之间交互的状态,确保Client与Service之间交互唯一性(SessionId),即:多个Client同时访问Service,Service能够区别;
2.ASP.NET&Session 与 WCF&Session区别:
在WCF中,Session属于Service Contract的范畴,并在Service Contract定义中通过参数来实现。WCF中会话具有以下几个重要的特征:
Session都是由Client端显示启动和终止的。
  在WCF中Client通过创建的代理对象来和服务进行交互,在支持Session的默认情况下,Session是和具体的代理对象绑定在一起,当Client通过调用代理对象的某个方法来访问服务时,Session就被初始化,直到代理的关闭,Session则被终止。我们可以通过两种方式来关闭代理:一是调用,二是调用&。我们也可以通过服务中的某个操作方法来初始化、或者终止Session,可以通过OperationContractAttribute的IsInitiating和参数来指定初始化和终止Session的Operation。
在WCF会话期间,传递的消息按照它发送的顺序被接收。
WCF并没有为Session支持保存相关的状态数据。
  而Asp.net中的Session具有以下特性:
Asp.net的Session总是由服务端启动的,即在服务端进行初始化的。
Asp.net中的Session是无序的,不能保证请求处理是有序的。
Asp.net是通过在服务端以某种方式保存State数据来实现对Session的支持,例如保存在Web Server端的内存中。
二、WCF实例管理
对于Client来说,它实际上不能和Service进行直接交互,它只能通过客户端创建的Proxy来间接地和Service进行交互,然而真正的调用而是通过服务实例来进行的。我们把通过Client的调用来创建最终的服务实例过程称作激活,在.NET Remoting中包括Singleton模式、SingleCall模式和客户端激活方式,WCF中也有类似的服务激活方式:单调服务(PerCall)、会话服务(PerSession)和单例服务(Singleton)。
单调服务(Percall):为每个客户端请求分配一个新的服务实例。类似.NET Remoting中的SingleCall模式
会话服务(Persession):在会话期间,为每次客户端请求共享一个服务实例,类似.NET Remoting中的客户端激活模式。
单例服务(Singleton):所有客户端请求都共享一个相同的服务实例,类似于.NET Remoting的Singleton模式。但它的激活方式需要注意一点:当为对于的服务类型进行Host的时候,与之对应的服务实例就被创建出来,之后所有的服务调用都由这个服务实例进行处理。
1.WCF中服务激活的默认方式是PerSession,但不是所有的Bingding都支持Session,比如BasicHttpBinding就不支持Session。
2.通过在服务契约接口上ServiceContract(SessionMode = 会话模式)来显式设置会话模式,禁用会话模式,可设为:SessionMode.NotAllowed
3.通过在Service实现类上ServiceBehavior(InstanceContextMode=激活方式)来显式设置服务实例激活方式
三、运用WCF 的单例服务(Singleton)及会话模式,实现系统同一时间只能允许同一用户名登录(即:单次登录),代码如下:
1.定义服务契约及创建服务类
using System.ServiceM
namespace WcfServiceLibrary1
[ServiceContract(SessionMode = SessionMode.Required)]
public interface ILogin
[OperationContract]
string Login(string username, string password);
[OperationContract(IsOneWay=true)]
void Logout();
using System.Collections.G
using System.ServiceM
namespace WcfServiceLibrary1
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class LoginService:ILogin
private Dictionary&string,string& loginU
public LoginService()
this.loginUsers = new Dictionary&string, string&();
public string Login(string username, string password)
if (!string.IsNullOrEmpty(username) && password == &123456&)
if (!this.loginUsers.ContainsValue(username))
this.loginUsers.Add(OperationContext.Current.SessionId,username);
return null;
return string.Format(&用户{0}已在其它地方有登录,同一时间不允许同一用户重复登录!&, username);
return &用户名或密码错误!&;
public void Logout()
this.loginUsers.Remove(OperationContext.Current.SessionId);
2.创建宿主程序
CONFIG配置文件:
&?xml version=&1.0& encoding=&utf-8& ?&
&configuration&
&system.serviceModel&
&behaviors&
&behavior name=&LoginServicemetadatabehavior&&
&serviceMetadata httpGetEnabled=&true&/&
&/behavior&
&/behaviors&
&services&
&service name=&WcfServiceLibrary1.LoginService& behaviorConfiguration=&LoginServicemetadatabehavior&&
&endpoint address=&& binding=&wsHttpBinding& contract=&WcfServiceLibrary1.ILogin&&&/endpoint&
&baseAddresses&
&add baseAddress=&http://127.0.0.1:10900/LoginService&/&
&/baseAddresses&
&/service&
&/services&
&/system.serviceModel&
&/configuration&
代码部份:
using WcfServiceLibrary1;
using System.ServiceM
using System.ServiceModel.D
namespace ConsoleApplicationHost
class Program
static void Main(string[] args)
BuildLoginServiceHostByConfig();
static void BuildLoginServiceHostByConfig()
using (ServiceHost host = new ServiceHost(typeof(LoginService)))
host.Opened += (s, e) =& { Console.WriteLine(&LoginService已经启动,按按回车键终止服务!&); };
host.Open();
Console.ReadLine();
3.在客户端程序调用WCF服务
首先添加并引用WCF服务,VS自动生成WCF服务相关的接口与代理类,这里是:LoginClient
然后就可以直接使用LoginClient来调用WCF服务相关方法,代码如下:
using System.ServiceM
using WcfServiceLibrary1;
namespace ConsoleApplicationClient
class Program
static void Main(string[] args)
CallLoginService();
Console.WriteLine(&按任意键结束。&);
Console.Read();
static void CallLoginService()
using (LoginServices.LoginClient proxy = new LoginServices.LoginClient())
Console.Write(&请输入用户名:&);
string input1 = Console.ReadLine();
Console.Write(&请输入密码:&);
string input2 = Console.ReadLine();
string loginResult = proxy.Login(input1, input2);
if (!string.IsNullOrEmpty(loginResult))
Console.WriteLine(loginResult);
Console.WriteLine(&恭喜你,登录成功!&);
Console.Write(&若需登出,请输入Y:&);
string input3 = Console.ReadLine();
if (input3 == &Y&)
proxy.Logout();
Console.WriteLine(&登出成功!&);
如果同时打开多个客户端程序,并输入相同的用户名,只要有一个登录成功或登录成功后不登出,其余的均会登录不上,报错!效果如下图示:
当然也可以利用其它激活方式实现更多功能,在此就不再重述,原理相同!
本文参考与引用了以下作者的文章:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
(10)(15)(6)(18)(2)(13)(12)(18)(28)(5)(24)(40)(21)(17)(27)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'WCF - 服务实例管理模式 - 李sir - 博客园
WCF 提供了三种实例上下文模式:PreCall、PreSession 以及 Single。开发人员通过 ServiceBehavior.InstanceContextMode 就可以很容易地控制服务对象的实例管理模式。而当 WCF 释放服务对象时,会检查该对象是否实现了 IDisposable 接口,并调用其 Dispose 方法,以便及时释放相关资源,同时也便于我们观察对象释放行为。1. PreCall在 PreCall 模式下,即便使用同一个代理对象,也会为每次调用创建一个服务实例。调用结束后,服务实例被立即释放(非垃圾回收)。对于不支持 Session 的 Binding,如 BasicHttpBinding,其缺省行为就是 PreCall。
[ServiceContract]
public interface IMyService
[OperationContract]
void Test();
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyServie : IMyService, IDisposable
public MyServie()
Console.WriteLine("Constructor:{0}", this.GetHashCode());
[OperationBehavior]
public void Test()
Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
public void Dispose()
Console.WriteLine("Dispose");
public class WcfTest
public static void Test()
AppDomain.CreateDomain("Server").DoCallBack(delegate
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri(""));
host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
host.Open();
//-----------------------
IMyService channel = ChannelFactory&IMyService&.CreateChannel(new WSHttpBinding(),
new EndpointAddress(""));
using (channel as IDisposable)
channel.Test();
channel.Test();
输出:Constructor:Test:urn:uuid:dfba-4c54-a533d9b4DisposeConstructor:Test:urn:uuid:dfba-4c54-a533d9b4Dispose2. PreSessionPreSession 模式需要绑定到支持 Session 的 Binding 对象。在客户端代理触发终止操作前,WCF 为每个客户端维持同一个服务对象,因此 PreSession 模式可用来保持调用状态。也正因为如此,PreSession 在大并发服务上使用时要非常小心,避免造成服务器过度负担。虽然支持 Session 的 Binding 对象缺省就会启用 PreSession 模式,但依然建议你强制指定 SessionMode.Required 和 InstanceContextMode.PerSession。
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IMyService
[OperationContract]
void Test();
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyServie : IMyService, IDisposable
public MyServie()
Console.WriteLine("Constructor:{0}", this.GetHashCode());
[OperationBehavior]
public void Test()
Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
public void Dispose()
Console.WriteLine("Dispose");
public class WcfTest
public static void Test()
AppDomain.CreateDomain("Server").DoCallBack(delegate
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri(""));
host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
host.Open();
//-----------------------
IMyService channel = ChannelFactory&IMyService&.CreateChannel(new WSHttpBinding(),
new EndpointAddress(""));
using (channel as IDisposable)
channel.Test();
channel.Test();
输出:Constructor:Test:urn:uuid:2f01b61d-40c6-4f1b-a4d6-4f4bc3e8847aTest:urn:uuid:2f01b61d-40c6-4f1b-a4d6-4f4bc3e8847aDispose3. Single一如其名,服务器会在启动时,创建一个唯一(Singleton)的服务对象。这个对象为所有的客户端服务,并不会随客户端终止而释放。
[ServiceContract]
public interface IMyService
[OperationContract]
void Test();
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyServie : IMyService, IDisposable
public MyServie()
Console.WriteLine("Constructor:{0}; {1}", DateTime.Now, this.GetHashCode());
[OperationBehavior]
public void Test()
Console.WriteLine("Test:{0}; {1}", DateTime.Now, OperationContext.Current.SessionId);
public void Dispose()
Console.WriteLine("Dispose:{0}", DateTime.Now);
public class WcfTest
public static void Test()
AppDomain.CreateDomain("Server").DoCallBack(delegate
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri(""));
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.Open();
//-----------------------
for (int i = 0; i & 2; i++)
IMyService channel = ChannelFactory&IMyService&.CreateChannel(new BasicHttpBinding(),
new EndpointAddress(""));
using (channel as IDisposable)
channel.Test();
channel.Test();
输出:Constructor: 17:31:01; Test: 17:31:03;Test: 17:31:03;Test: 17:31:03;Test: 17:31:03;还有另外一种方式来启动 Single ServiceHost。
AppDomain.CreateDomain("Server").DoCallBack(delegate
MyServie service = new MyServie();
ServiceHost host = new ServiceHost(service, new Uri(""));
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.Open();
此方式最大的好处是允许我们使用非默认构造,除此之外,和上面的例子并没有什么区别。需要特别注意的是,缺省情况下,Single 会对服务方法进行并发控制。也就是说,多个客户端需要排队等待,直到排在前面的其他客户端调用完成后才能继续。看下面的例子。
[ServiceContract]
public interface IMyService
[OperationContract]
void Test();
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyServie : IMyService, IDisposable
public MyServie()
Console.WriteLine("Constructor:{0}", this.GetHashCode());
[OperationBehavior]
public void Test()
Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
Thread.Sleep(2000);
Console.WriteLine("Test End:{0}", OperationContext.Current.SessionId);
public void Dispose()
Console.WriteLine("Dispose");
public class WcfTest
public static void Test()
AppDomain.CreateDomain("Server").DoCallBack(delegate
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri(""));
host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
host.Open();
//-----------------------
for (int i = 0; i & 2; i++)
new Thread(delegate()
IMyService channel = ChannelFactory&IMyService&.CreateChannel(new WSHttpBinding(),
new EndpointAddress(""));
using (channel as IDisposable)
while (true)
channel.Test();
}).Start();
输出:Constructor:Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfcTest End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfcTest:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfcTest End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfcTest:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfcTest End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc...我们可以通过修改并发模式(ConcurrencyMode)来改变这种行为,但需要自己维护多线程安全。
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
public class MyServie : IMyService, IDisposable
输出:Constructor:Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3cTest:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3cTest:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3cTest End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3cTest:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3cTest End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3cTest:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3cTest End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(1404)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_080069',
blogTitle:'WCF中实例模式(InstanceContextMode)与会话模式(SessionMode) - tianxd - 博客园',
blogAbstract:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

我要回帖

更多关于 java建造者模式实例 的文章

 

随机推荐