加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net – 在Azure中的不同实例(可能在Web场中)中更改SessionID

发布时间:2020-12-16 03:54:58 所属栏目:asp.Net 来源:网络整理
导读:我有一个带有一个WebRole的Azure项目有问题,但有多个实例使用无cookie会话.该应用程序不需要会话存储,因此它不使用任何会话存储提供程序,但我需要跟踪SessionID.显然,the SessionID should be the same accross the WebRole instances,但它突然变化没有解释.
我有一个带有一个WebRole的Azure项目有问题,但有多个实例使用无cookie会话.该应用程序不需要会话存储,因此它不使用任何会话存储提供程序,但我需要跟踪SessionID.显然,the SessionID should be the same accross the WebRole instances,但它突然变化没有解释.我们使用SessionID来跟踪一些数据,因此非常重要.

为了重现这个问题:

>创建云项目.
>添加ASP.NET Web角色.已有的代码可以.
>打开Default.aspx
>添加一个控件以查看当前的SessionID和一个导致回发的按钮

<p><%= Session.SessionID %></p>
        <asp:Button ID="Button1" runat="server" Text="PostBack" onclick="Button1_Click" />

>为按钮添加一个事件处理程序,它会稍微延迟响应:

protected void Button1_Click(object sender,EventArgs e)
{
    System.Threading.Thread.Sleep(150);
}

>打开Web.Config
>启用无cookie会话:

<system.web>
        <sessionState cookieless="true" />
</system.web>

>运行项目,快速点击“PostBack”按钮一段时间,注意地址栏中的会话ID.什么都没发生,会话ID始终是相同的:).停下来.
>打开ServiceConfiguration.csfg
>启用四个实例:

<Instances count="4" />

>确保在Web.config中有一行与Visual Studio自动添加的机器密钥相关联. (在system.web的末尾).
>重新运行项目,快速点击“Postback”按钮一段时间,并注意地址栏中的会话ID.您将看到SessionID在一段时间后如何变化.

为什么会这样?据我所知,如果所有机器共享machineKey,则会话应该是相同的.使用cookie没有问题,问题显然是在使用无cookie会话时.

我最好的猜测是,当存在多个实例时,当一个WebRole中生成的SessionID转到另一个时,会被拒绝并重新生成.这没有意义,因为所有的WebRoles都有相同的machineKey.

为了找出问题并更清楚地看到它,我创建了自己的SessionIDManager:

public class MySessionIDManager : SessionIDManager
{
    public override string CreateSessionID(HttpContext context)
    {
        if (context.Items.Contains("AspCookielessSession"))
        {
            String formerSessionID = context.Items["AspCookielessSession"].ToString();

           // if (!String.IsNullOrWhiteSpace(formerSessionID) && formerSessionID != base.CreateSessionID(context))
               // Debugger.Break();

            return formerSessionID;
        }
        else
        {
            return base.CreateSessionID(context);
        }
    }
}

并使用它在WebConfig中更改此行:

<sessionState cookieless="true" sessionIDManagerType="WebRole1.MySessionIDManager" />

现在你可以看到SessionID不会改变,无论你打多快多快.如果取消注释这两行,您将看到ASP.NET如何创建新的sessionID,即使已经存在.

为了强制ASP.NET创建新会话,只需重定向到站点中的绝对URL:

Response.Redirect(Request.Url.AbsoluteUri.Replace(Request.Url.AbsolutePath,String.Empty));

为什么这个事情发生在无cookie会话中?

我在MySessionIDManager中的解决方案有多可靠?

亲切的问候.

更新:

>我尝试过这种解决方法:
User-Specified Machine Keys
Overwritten by Site-Level Auto
Configuration,但问题
仍然站着.

public override bool OnStart()
{
    // For information on handling configuration changes
    // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.

    using (var server = new ServerManager())
    {
        try
        {
            // get the site's web configuration
            var siteNameFromServiceModel = "Web"; // update this site name for your site. 
            var siteName =
                string.Format("{0}_{1}",RoleEnvironment.CurrentRoleInstance.Id,siteNameFromServiceModel);
            var siteConfig = server.Sites[siteName].GetWebConfiguration();

            // get the appSettings section
            var appSettings = siteConfig.GetSection("appSettings").GetCollection()
                .ToDictionary(e => (string)e["key"],e => (string)e["value"]);

            // reconfigure the machine key
            var machineKeySection = siteConfig.GetSection("system.web/machineKey");
            machineKeySection.SetAttributeValue("validationKey",appSettings["validationKey"]);
            machineKeySection.SetAttributeValue("validation",appSettings["validation"]);
            machineKeySection.SetAttributeValue("decryptionKey",appSettings["decryptionKey"]);
            machineKeySection.SetAttributeValue("decryption",appSettings["decryption"]);

            server.CommitChanges();
            _init = true;
        }
        catch
        {
        }
    }
    return base.OnStart();
}

>我也在put a
session start handler尝试了这个并添加
一些数据,但没有运气.

void Session_Start(object sender,EventArgs e)
{
    Session.Add("dummyObject","dummy");
}

赏金!

解决方法

简而言之,除非您使用cookie或会话提供程序,否则会话ID无法从一个Web角色实例传递到另一个Web角色实例.您提到的帖子表示,如果您不使用Cookie或会话存储,则SessionID不会在Web角色中保持不变.
检查此 previous question以了解处理Azure中的状态存储的方法,例如使用表存储

machineKey与会话或应用程序域无关,它是用于encrypt,decrypt,validate身份验证和查看状态数据的密钥.要使用Reflector验证此打开的SessionIDManager.CreateSessionID.您将看到ID值只是一个随机的16字节值,编码为字符串.

SessionIDManager已经在GetSessionID方法中检查了AspCookielessSession值,而不是CreateSessionID,因此在代码执行之前检查已经完成.由于默认的会话状态模式是InProc,因此单独的Web角色将无法验证会话密钥,因此它们会创建一个新的.

事实上,角色可以随时迁移到不同的物理机器,在这种情况下,它的状态将会丢失.来自SQL Azure团队的这篇文章正是出于这个原因描述了一种到use SQL Azure to store state的方法.

编辑我终于让TableStorageSessionStateProvider在无cookie模式下工作!

虽然TableStorageSessionStateProvider通过覆盖SessionStateStoreProviderBase.CreateUnititializedItem确实支持cookieless模式,但它无法在私有SessionStateStoreData GetSession中正确处理空会话(HttpContext上下文,字符串id,out bool锁定,out TimeSpan lockAge,out对象lockId,out SessionStateActions操作,bool独占).如果在底层blob存储中找不到数据,解决方案是返回一个空的SessionStateStoreData.

该方法长145行,所以我不会在这里粘贴它.搜索以下代码块

if (actions == SessionStateActions.InitializeItem) 
{
     // Return an empty SessionStateStoreData                    
     result = new SessionStateStoreData(new SessionStateItemCollection(),}

创建新会话时,此块将返回空会话数据对象.不幸的是,空数据对象没有存储到blob存储器中.

如果blob为空,则使用以下行替换第一行以使其返回空对象:

if (actions == SessionStateActions.InitializeItem || stream.Length==0)

只要提供程序支持,就可以使用long stroy short cookieles会话状态.您必须决定使用示例提供程序是否使用无cookie状态.也许vtortola应该检查AppFabric Caching CTP.它包括开箱即用的ASP.NET提供程序,速度要快得多,它肯定比示例提供程序有更好的支持.关于如何设置会话状态甚至还有step-by-step tutorial.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读