一、理解Session

1.Session的作用:保留Client和Service之间交互的状态,确保Client与Service之间交互唯一性(SessionId),即:多个Client同时访问Service,Service能够区别;

2.ASP.NET Session 与 WCF Session区别:

在WCF中,Session属于Service Contract的范畴,并在Service Contract定义中通过SessionModel参数来实现。WCF中会话具有以下几个重要的特征:

  • Session都是由Client端显示启动和终止的。

  在WCF中Client通过创建的代理对象来和服务进行交互,在支持Session的默认情况下,Session是和具体的代理对象绑定在一起,当Client通过调用代理对象的某个方法来访问服务时,Session就被初始化,直到代理的关闭,Session则被终止。我们可以通过两种方式来关闭代理:一是调用ICommunicationObject.Close 方法,二是调用ClientBase<TChannel>.Close 方法 。我们也可以通过服务中的某个操作方法来初始化、或者终止Session,可以通过OperationContractAttribute的IsInitiating和IsTerminating参数来指定初始化和终止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.ServiceModel;

namespace WcfServiceLibrary1
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface ILogin
{
[OperationContract]
string Login(string username, string password); [OperationContract(IsOneWay=true)]
void Logout();
}
} using System.Collections.Generic;
using System.ServiceModel; namespace WcfServiceLibrary1
{
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class LoginService:ILogin
{
private Dictionary<string,string> loginUsers; public LoginService()
{
this.loginUsers = new Dictionary<string, string>();
} public string Login(string username, string password)
{
if (!string.IsNullOrEmpty(username) && password == "")
{
if (!this.loginUsers.ContainsValue(username))
{
this.loginUsers.Add(OperationContext.Current.SessionId,username);
return null;
}
else
{
return string.Format("用户{0}已在其它地方有登录,同一时间不允许同一用户重复登录!", username);
}
}
else
{
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>
<host>
<baseAddresses>
<add baseAddress="http://127.0.0.1:10900/LoginService"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

代码部份:

using System;
using WcfServiceLibrary1;
using System.ServiceModel;
using System.ServiceModel.Description; 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;
using System.ServiceModel;
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);
return;
} Console.WriteLine("恭喜你,登录成功!");
Console.Write("若需登出,请输入Y:");
string input3 = Console.ReadLine();
if (input3 == "Y")
{
proxy.Logout();
Console.WriteLine("登出成功!");
} }
}
}
}

如果同时打开多个客户端程序,并输入相同的用户名,只要有一个登录成功或登录成功后不登出,其余的均会登录不上,报错!效果如下图示:

当然也可以利用其它激活方式实现更多功能,在此就不再重述,原理相同!

本文参考与引用了以下作者的文章:

跟我一起学WCF(8)——WCF中Session、实例管理详解

WCF会话(Session)与实例(Instance)管理的更多相关文章

  1. 跟我一起学WCF(8)——WCF中Session、实例管理详解

    一.引言 由前面几篇博文我们知道,WCF是微软基于SOA建立的一套在分布式环境中各个相对独立的应用进行交流(Communication)的框架,它实现了最新的基于WS-*规范.按照SOA的原则,相对独 ...

  2. 使用SpringSession管理分布式系统的会话Session

    在我方供应链项目分布式部署的环境下,需要在统一网关服务中管理访问的Session,即无论访问请求路由到哪一个网关服务环境,使用的都是相同的HttpSession,这样就保证了在用户登录之后,能够使用统 ...

  3. Oracle 启动实例(instance)、打开数据库

    Oracle启动实例(instance).打开数据库   by:授客 QQ:1033553122 启动实例(instance).打开数据库 1.开启sqlplus [laiyu@localhost ~ ...

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

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

  5. WCF服务类的实例模式(本文为转载)

    WCF开发时如何选择正确的实例模式(InstanceMode)?   在使用WCF实例模型时,你是否思考过这几个的问题: ”WCF中的实例模式如何正确应用”? ”使用WCF中的实例模式有何原则可以遵循 ...

  6. MyBatis之会话Session原理

    MyBatis 之会话 Session 执行逻辑 1.SQL 会话工厂构建器类 SqlSessionFactoryBuilder 的 build 方法用于构建 SqlSessionFactory 类的 ...

  7. 简单PHP会话(session)说明

    现在程序员愈发的不容易了,想要精通,必然要寻本溯源,这其实与目前泛滥的愈发高级的语言以及众多的框架刚好相反,因为它们在尽可能的掩盖本源使其简单,个人称之为程序员学习悖论. 注:作者接触web开发和ph ...

  8. PHP之session相关实例教程与经典代码

    ·php 中cookie和session的用法比较 ·phpmyadmin报错:Cannot start session without errors问题 ·php中cookie与session应用学 ...

  9. Tensorflow会话Session

    转载自: http://blog.csdn.net/Hanging_Gardens/article/details/72784392 https://www.cnblogs.com/hypnus-ly ...

随机推荐

  1. Oracle PL/SQL块

    PL/SQL块 简介 :PL/SQL是 Procedure Language & Structured Query Language 的缩写,是ORACLE公司对标准数据库语言的扩展 PL/S ...

  2. [.net 面向对象编程基础] (12) 面向对象三大特性——继承

    [.net 面向对象编程基础] (12) 面向对象三大特性——继承 上节我们说了面向对象的三大特性之一的封装,解决了将对同一对象所能操作的所有信息放在一起,实现统一对外调用,实现了同一对象的复用,降低 ...

  3. 扩展GridView控件——为内容项添加拖放及分组功能

    引言 相信大家对GridView都不陌生,是非常有用的控件,用于平铺有序的显示多个内容项.打开任何WinRT应用或者是微软合作商的网站,都会在APP中发现GridView的使用.“Tiles”提供了一 ...

  4. SQL—大话函数依赖与范式

    说明:数据库中的某些概念真的很让人头疼,概念的东西本来就是很枯燥的,再加上枯燥的学习,那就更加枯燥了.概念这东西,你不理解也能生产东西,经验多了就行,但是为了更深入的学习,你还必须理解.这里,我抛开书 ...

  5. Atitit js中的依赖注入di ioc的实现

    Atitit js中的依赖注入di ioc的实现 全类名(FQCN)为标识符1 混合请求模式1 使用类内  builder  即可..2 Service locator method走ok拦2 Jav ...

  6. Atitit vod click event design flow  视频点播系统点击事件文档

    Atitit vod click event design flow  视频点播系统点击事件文档 重构规划1 Click cate1 Click  mov4 重构规划 事件注册,与事件分发管理器分开 ...

  7. Piwik 扩展获取客户端IP地址

    piwik 数据库浏览记录存放在piwik_log_visit表中 piwik_log_visit 表有个location_ip字段,该字段存储为Byte[]字节 解析出来后的IP地址为 XXX.XX ...

  8. js防止客户端多触发

    代码: /***防止多触发**id 必须唯一*fn 回掉函数*wait 延迟多长时间**使用例子:* ToPreventMoreTrigger('id', function () {//注意 id 是 ...

  9. 练习2 练习目标-使用引用类型的成员变量:在本练习中,将扩展银行项目,添加一个(客户类)Customer类。Customer类将包含一个Account对象。

    package banking; public class Customer { private String firstName; private String lastName; private ...

  10. Unity3D Editor模式下批量修改prefab

    最经遇到一个需要批量修改已经做好的prefab的问题,查了一些资料最终实现了但是还是不够完美,通过学习也发现unity的编辑器功能还是非常强大的.废话不多说直接上代码: [ExecuteInEditM ...