本文主要是通过sql server来实现session共享,经过本人测试:
Asp.Net提供了以下几种Session保存机制,如表 1所示:
方式名称 | 存储方式 | 性能 |
Off | 设置为不使用Session功能 | 无 |
InProc | 设置为将Session存储在进程内,就是ASP中的存储方式,这是默认值 | 最高 |
StateServer | 设置为将Session存储在独立的状态服务中。通常是aspnet_state.exe进程 | 性能损失10-15% |
SQLServer | 设置将Session存储在SQL Server中。 | 性能损失10-20% |
Custom | 自定制的存储方案 | 由实现方式确定 |
在Asp.Net程序的web.config配置文件中对Session的保存方式进行设置。如果不显示指定Session的保存方式,默认使用InProc的方式保存,即Session由提供服务的工作进程保存。
为了提高IIS对高并发的支持,可以增加应用程序池的工作进程数,IIS会根据内置的调度算法,将用户的请求在多个工作进程间动态分配,如果搭建了服务器集群和负载均衡,则用户请求会在多台机器的多个工作进程间进行动态分配。在上述情况下,如果Session的保存方式依然为InProc,则用户请求在多个工作进程间切换时可能出现Session丢失的情况,导致请求失败或出错。
为解决上述为,需要将Session的保存方式设置为共享,即表 1中的“StateServer”、“SQLServer”或“Custom”方式。这几种方法中,“SQLServer”方式需要安装独立的SQLServer数据库,“Custom”方式需要自行实现相应的Session存储与检索过程,部署起来相对复杂,相对上述两种方式,“StateServer”方式在功能性和可实施性上最好。
二、什么是cookie?
大家平时在登录网页时有一个记住用户名的选项,等下次登录会填充用户名,甚至有的会自动填充用户名和密码,这样就会很方便用户。那它是怎么实现的呢?其实很简单就是通过cookie保存在浏览器中,如下图,这是163.com存在谷歌浏览器中的cookie,用户在浏览器输入url时,浏览器会将该域名下存储的cookie放在http的head中发送到服务器(浏览器不能把其他域名的cookie也发送到服务器,不然这就乱套了,这么多cookie,什么还有重名的,于是乎这就产生了cookie的跨域,关于cookie的跨域请听下文分解。)然后服务器给控件赋值,于是就达到了自动填充的效果。可能会觉得这样不安全,人家能监听到你的cookie信息,比如用户名密码这些,确实,这也是有一定的弊端,有的做的完善的会进行一些加密,但加密也是需要消耗额外的资源的,所以都是有利有弊吧。而且最重要的是浏览器每次请求都会将对应的cookie发送给服务器,服务器又会把cookie响应给客户端,cookie内容多的时候,可想而知,系统就会变慢,所以性能优化有一条就是对cookie优化,性能优化又是一个新的大陆。
三、session和cookie的关系
关于什么是session,对我来说没有十万个为什么也有一二十个。它是怎么来的又是怎么没的,HTTP本身是无状态的,客户端和服务端又是怎么个的眉来眼去的让服务器知道是同一个用户的操作呢?每个用户登录之后都会在服务器保存session["UserName"],那这么多的session["UserName"],怎么确保A用户获取的session["UserName"]就是它本人的,不是其他用户的呢?对于每次请求都会实例化一个session对象,这个session对象有一个sessionId,当用户设置session["UserName"]后,那这个session对象就会存在服务器中,如果session对象中没有那就会被销毁。保存在服务器中之后,响应给浏览器时会把这个session对象对应的sessionid放在cookie中,这样浏览器下次再请求时就会把这个sessionid带上,然后就能根据sessid找到这个session对象了,而不至于找到别的。在下图可以找到sessionID,设置的session["UserName"]放在session对象的keys熟悉中。Mode时InProc模式,就是放在IIS中。
四、Session共享设置
要想共享,多个应用用一份,那就得先把session分离出来,不然怎么做到共享。
1.启动ASP.NET State Service服务
2.在数据库服务器执行sql
sql文件在C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallSqlState.sql,InstallSqlState.sql是注册,UninstallSqlState.sql是取消。执行完之后只是创建了ASPState数据库,并未创建表如下图,还提示我使用aspnet_regsql.exe去install sql session state。以及启动SQLServer Agent.
3.启动SQLServerAgent
4.注册SQL Session State
原本想着直接运行aspnet_regsql.exe注册,但打开之后提示要用命令行,已经提示用此向导创建或配置成员、角色 事件的,对于回话状态用命令行。
于是乎根据提示cmd命令行 aspnet_regsql.exe -?出现下面的使用方法
由于是我在本地的数据库上所以执行的是我本地的数据库服务器的名字:aspnet_regsql.exe -S PC-201611282159 -E -ssadd -sstype p
注册完成之后ASPState数据库就存在了两张表:ASPStateTempApplications,ASPStateTempSessions
从表结构能看出来有appid和appname,这就导致了默认是一个应用一个id和name,那这样是共享不了的,怎么共享呢?其实也比较容易,只需需改下存储过程TempGetAppID中的WHERE AppName = @appName注释掉,然后重启就好了。
五、demo
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebForm
{
public partial class Index : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Session["UserName"] = "CuiYW";
HttpCookie cookie = new HttpCookie("UserInfo");
Request.Cookies.Add(cookie);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVC.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
if (Session["UserName"] != null)
{
ViewBag.UserName = Session["UserName"];
}
return View();
}
}
}
同时要在webconfig的<system.web>中都要配置
<sessionState mode="SQLServer" allowCustomSqlDatabase="true" sqlConnectionString="server=PC-201611282159; database=ASPState;Trusted_Connection=true;"
timeout="20" >
先运行WebForm设置session,然后运行MVC,在View中显示ViewBag.UserName.结果是可以获取到,这就意味着实现了共享。
然后就搞定了。