zoukankan      html  css  js  c++  java
  • 最好的(自我感觉)实现多个ASP.NET跨程序池共享Session [转]

    最好的(自我感觉)实现多个ASP.NET跨程序池共享Session [转]

    简要介绍,本文主要内容是实现通过ASP.NET自己的Sql Server的Session存储机制实现,通过存储过程实现忽略程序标识的区别,达到多程序池间Session数据共享的目的。详细原文:

    本文转载人数己经太多,所以不知道原文地址何处,敬请谅解!

    我的链接地址是http://space.itpub.net/12639172/viewspace-675757

    大致思路:
    采用SqlServer方式存储Session,分析数据库表结构、原理、流程,大致可以得到SqlServer存储Session的方法:
    表结构:

    ASPStateTempApplications表存储应用程序Id及名称
    ASPStateTempSessions表存储具体的Session值
    不同的应用程序会在ASPStateTempApplications中注册不同的数据,从而在ASPStateTempSessions中有不同的Session,如果要实现Session共享,可以用欺骗SqlServer的方法:用某种方法使得不同的应用程序访问数据库时用相同的App!为了达到这个目的,分析[dbo].[TempGetAppID]这个存储过程,代码如下:

    1 ALTER PROCEDURE [dbo].[TempGetAppID]
    2 @appName tAppName,
    3 @appId int OUTPUT
    4 AS
    5 SET @appName = LOWER(@appName)
    6 SET @appId = NULL
    7
    8 SELECT @appId = AppId
    9 FROM [Herald.Session].dbo.ASPStateTempApplications
    10 WHERE AppName = @appName
    11
    12 IF @appId IS NULL BEGIN
    13 BEGIN TRAN
    14
    15 SELECT @appId = AppId
    16 FROM [Herald.Session].dbo.ASPStateTempApplications WITH (TABLOCKX)
    17 WHERE AppName = @appName
    18
    19 IF @appId IS NULL
    20 BEGIN
    21 EXEC GetHashCode @appName, @appId OUTPUT
    22
    23 INSERT [Herald.Session].dbo.ASPStateTempApplications
    24 VALUES
    25 (@appId, @appName)
    26
    27 IF @@ERROR = 2627
    28 BEGIN
    29 DECLARE @dupApp tAppName
    30
    31 SELECT @dupApp = RTRIM(AppName)
    32 FROM [Herald.Session].dbo.ASPStateTempApplications
    33 WHERE AppId = @appId
    34
    35 RAISERROR('SQL session state fatal error: hash-code collision between applications ''%s'' and ''%s''. Please rename the 1st application to resolve the problem.',
    36 18, 1, @appName, @dupApp)
    37 END
    38 END
    39
    40 COMMIT
    41 END
    42
    43 RETURN 0

    可以看到传入参数是AppName,通过AppName获取AppId,如果不存在则在ASPStateTempApplications表中插入该条记录,这里AppName参数在传入时是不同的应用程序不同的,当然我们可以在这里小改一下...注意第5行SET @appName = LOWER(@appName) 我们可以毫不客气的改成SET @appName = 'Everything you want ^_^'
    好了(不知道这样做微软会不会很不悦...),大功告成,清理残留的Session,最好重启一下IIS,不用修改旧程序本身丝毫(配置web.config除外),实现了Session共享...以后凡是使用该数据库作为Session存储的都可以共享Session了...
    其他的一些配置说明如下:
    配置web.config节:

    <sessionState mode="SQLServer" sqlConnectionString="data source=[Server];initial catalog=[DataBase];user id=[UserName];password=[Password]" allowCustomSqlDatabase="true" timeout="120"/>

    复制代码

    配置SQLServer:

    aspnet_regsql.exe -sstype c -ssadd -d [DataBase] -U [UserName] -P [Password] -S [Server]

    修改[dbo].[TempGetAppID]:将@appName设为一个定值,修改保存。
    清理Session,重启IIS,KO!
    另外:这个方法其实很Bug 嘿嘿 再多研究下数据库的存储过程或者用某种方法定制appName的话,可能可以实现更多的功能。

    只这样还不够,需要将Session的Cookie写到客户端,可以让多个程序进行读取。

    今天, 我要写的是如何在二级域名站点之间,主站点和二级域名站点之间共享Session。

    首先, Session要共享,站点之间SessionID必须要一致,那怎么保证SessionID一致呢?

    ASP.NET中的SessionID是存储在客户端的cookie之中键值为ASP.NET_SessionId用来维护浏览者Session对应关系的一个字符串,要想在二级域名站点之间,主站点和二级域名站点共享SessionID就必须先共享,那么我们就必须先实现ASP.NET_SessionId这一cookie的共享。

    CrossDomainCookieModule

    ------------------------------------------------------------------------------------------------

    publicclassCrossDomainCookie : IHttpModule
    {
    privatestringm_RootDomain=string.Empty;
    #regionIHttpModule Members
    publicvoidDispose()
    {
    }
    publicvoidInit(HttpApplication context)
    {
    m_RootDomain=ConfigurationManager.AppSettings["RootDomain"];
    context.EndRequest+=newSystem.EventHandler(context_EndRequest);
    }
    voidcontext_EndRequest(objectsender, System.EventArgs e)
    {
    HttpApplication app=senderasHttpApplication;
    for(inti=0; i<app.Context.Response.Cookies.Count; i++)
    {
    app.Context.Response.Cookies[i].Domain=m_RootDomain;
    }
    }
    #endregion
    }

    复制代码

    上面的Module重设了所有cookie的domain到root domain, root domain在web.config中设置。也许有人会说这是眉毛胡子一把抓重写了所有cookie的domain, 那他也可以判断一下cookie的name, 如果为ASP.NET_SessionId的话才重写。

    如果主站点和二级域名站点是同一站点,那么做到这一步,你的session就已经共享了,因为Session的ID是相同的,而且Session容器也是同一个。

    如果主站点和二级域名站点是两个不同站点,则需要进行更多的操作了。

    如果两个站点是不同的服务器的话,解决方法要简单点:

    1) 使用相同的state server来存储Session.

    2) 在两个站点的web.config设置相同的machineKey.

    MachineKey的设置请参考http://msdn.microsoft.com/zh-cn/asp.net/w8h3skw9.aspx

    3) 给两个站点设置相同name

    这样做是为了确保两个站点的siteID相同,siteID是site name的hash值,注意请不要使用默认站点,因为默认站点的siteID并非site name的hash.

    如果两个站点是在同一的服务器的话,需要对CrossDomainCookie再作一下修改,此方法也可应用于两个站点在不同服务器的情况:

    1) 使用相同的state server来存储Session.

    2) 用反射来设置System.Web.SessionState.OutOfProcSessionStateStore的静态字段s_uribase的值

    publicclassCrossDomainCookie : IHttpModule
    {
    privatestringm_RootDomain=string.Empty;
    #regionIHttpModule Members
    publicvoidDispose()
    {
    }
    publicvoidInit(HttpApplication context)
    {
    m_RootDomain=ConfigurationManager.AppSettings["RootDomain"];
    Type stateServerSessionProvider=typeof(HttpSessionState).Assembly.GetType("System.Web.SessionState.OutOfProcSessionStateStore");
    FieldInfo uriField=stateServerSessionProvider.GetField("s_uribase", BindingFlags.Static|BindingFlags.NonPublic);
    if(uriField==null)
    thrownewArgumentException("UriField was not found");
    uriField.SetValue(null, m_RootDomain);
    context.EndRequest+=newSystem.EventHandler(context_EndRequest);
    }
    voidcontext_EndRequest(objectsender, System.EventArgs e)
    {
    HttpApplication app=senderasHttpApplication;
    for(inti=0; i<app.Context.Response.Cookies.Count; i++)
    {
    app.Context.Response.Cookies[i].Domain=m_RootDomain;
    }
    }
    #endregion
    }

    复制代码

    完成这样的修改之后就可以实现Session的共享了。

    同样如果你是使用SQL server来存储Session, 也可以使用类似的方法来解决Session共享问题。

  • 相关阅读:
    通过注册表选择文件默认打开方式
    oracle的imp和exp
    oracle 10g正则表达式 REGEXP_LIKE 用法
    oracle varchar 和varchar2的区别
    Oracle lower(Upper)函数|大小写|
    NC资金管理对外付款自动选上“网上支付”设置
    wmsys.wm_concat的几个用法
    GridView使用初步
    JavaScript学习笔记(一)—细节问题
    图片水印功能
  • 原文地址:https://www.cnblogs.com/zbw911/p/2332692.html
Copyright © 2011-2022 走看看