c# - 服务器端 .NET Core 中的 Session.SetString() 产生错误 "The session cannot be established after the response has started"

标签 c# asp.net-core .net-core blazor blazor-server-side

我有一个服务器大小的 Blazor 应用程序,需要在首次加载页面时向 session 中写入一些内容,然后从该页面和其他页面中的 session 中读取它。

现在,Session.String() 在 OnInitializedAsync() 中调用。但是,我收到异常“响应开始后无法建立 session ”。从我发现的很少的文档来看,当 SignalR 与应用程序一起使用时,通常会发生这种情况。

1) 我认为我没有使用 SignalR,除非它默认配置为在服务器端 .net 核心代码中使用(在这种情况下,我如何找到?) 2)我还尝试将调用放入 OnInitialized() 和 onAfterRender() (同步方法)中,但这没有帮助。 3)我认为我的 HTTPContextAccessor 和 ISession 配置正确,因为我可以随时使用 Session.GetString() ,包括在调用 Session.SetString() 之前。 4) 由于多种原因,我无法切换到客户端大小的 Blazor 应用程序。 5)我使用的是app.UseEndpoints(),所以app.useMvc()被注释掉了,因为它们不能同时使用。

在我在这里粘贴大量代码之前,有谁能立即想到可能出了什么问题吗?到目前为止我所拥有的片段如下

//Startup.cs
public IHttpContextAccessor HtppContextAccessor { get; }
// ...

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddServerSideBlazor();

    services.AddHttpContextAccessor();

    //services.AddMvc(); //TODO: DO I NEED IT?
    services.AddDistributedMemoryCache();  //TODO : DO I NEED IT? // Adds a default in-memory implementation of IDistributedCache
    services.AddSession();

    //services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();


}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseSession();


    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();


    app.UseEndpoints(endpoints =>
    {
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });

}

//**************************************************************************
//myfile.razor

protected override async Task OnInitializedAsync()
{
    var sampleValue = Session.GetString("testName1"); //this call is ok
    Session.SetString("testName1", "testValue2"); //this is where exception occurs
}

谢谢

最佳答案

回答

我认为这个 Session.SetString() 错误是一个错误,因为 Session.GetString() 即使在响应开始后也能正常工作,但是 Session.SetString() 没有。无论如何,解决方法(或者“黑客”,如果你愿意的话)包括一次性调用 Session.SetString() 来“准备” session 以供将来写入。只需在应用程序中找到一行您知道响应尚未发送的代码,然后在其中插入对 Session.SetString() 的一次性调用即可。然后,您将能够在 OnInitializedAsync() 方法内对 Session.SetString() 进行无错误的后续调用,包括响应开始后的调用。您可以通过检查属性 HttpContext.Response.HasStarted 来检查响应是否已启动。

尝试将此 app.Use() 代码段添加到 Startup.cs Configure() 方法中:

...
...
app.UseHttpsRedirection();
app.UseStaticFiles();

//begin SetString() hack
app.Use(async delegate (HttpContext Context, Func<Task> Next)
{
    //this throwaway session variable will "prime" the SetString() method
    //to allow it to be called after the response has started
    var TempKey = Guid.NewGuid().ToString(); //create a random key
    Context.Session.Set(TempKey, Array.Empty<byte>()); //set the throwaway session variable
    Context.Session.Remove(TempKey); //remove the throwaway session variable
    await Next(); //continue on with the request
});
//end SetString() hack

app.UseRouting();


app.UseEndpoints(endpoints =>
{
    endpoints.MapBlazorHub();
    endpoints.MapFallbackToPage("/_Host");
});
...
...

背景信息

我可以在此处分享的信息并非特定于 Blazor,但将帮助您查明设置中发生的情况,因为我自己也遇到过同样的错误。

From scant documentation that I found, this usually happens when SignalR is used with the app.

我知道您说“通常会发生”,但只是为了澄清一下,在没有安装 SignalR 的情况下,此错误仍然可能发生;它并不是 SignalR 独有的。 SignalR 提到此错误的原因是因为 SignalR 使用 WebSockets。 WebSocket 很容易触发错误,因为 WebSocket 逻辑最常发生在 WebSocket 发送/接收 (ping/pong) 循环中,其中“响应”始终被“发送”。另外,Blazor 不也使用 WebSocket 吗?

无论如何,当同时满足以下条件两个时,就会发生错误:

标准 1. 向服务器发送的请求没有 session cookie,或者包含的 session cookie 无效/已过期。

条件 2。条件 1 中的请求在响应开始后调用 Session.SetString()。换句话说,如果属性HttpContext.Response.HasStartedtrue,并且调用Session.SetString(),则会抛出异常.

重要提示:如果不满足条件 1,则在响应开始后调用 Session.SetString() 不会导致错误。

...needs to write something into a session when page is first loaded...

这就是为什么错误似乎只在第一次加载页面时发生——因为通常在第一次加载时,服务器没有可以使用的 session cookie(或者提供的 session cookie 无效或太旧) ,并且服务器必须启动一个新的 session 数据存储(我不知道为什么它必须为 SetString() 启动一个新的 session 数据存储,这就是为什么我说我认为这是一个错误)。如果服务器必须启动新的 session 数据存储,它会在第一次调用 Session.SetString() 时执行此操作,并且新的 session 数据存储无法启动响应开始后。另一方面,如果提供的 session cookie 是有效的,则不需要启动新的数据存储,因此您可以随时调用 Session.SetString(),包括在响应已开始。

我敢打赌,在您的情况下,当调用 OnInitializedAsync() 时,属性 HttpContext.Response.HasStartedtrue,这就是抛出错误的原因。您需要做的是在响应开始之前对 Session.SetString() 进行初步调用,以便 session 数据存储启动,然后调用 Session.SetString() 。 OnInitializedAsync() 方法内的 SetString() 不会导致错误。

关于c# - 服务器端 .NET Core 中的 Session.SetString() 产生错误 "The session cannot be established after the response has started",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60660923/

相关文章:

c# - Linq Groupby 分类但我如何操作集合中的值

c# - 无法在 javascript 中获取 html 文本框的值

c# - UWP NetworkConnectionChanged 事件

c# - 从azure blob下载文件并出现空pdf页面

c# - 将空值绑定(bind)到 wpf 控件的宽度和高度时出现绑定(bind)错误

asp.net-core - Cookie认证: How to access a returning user

c# - 如何在 Asp.Net Core 2.2 中在运行时禁用/启用身份验证?

asp.net-core - 是否可以直接在 Azure WebApps 中的 Kestrel 上运行 ASP.NET 5 站点?

c# - 如何使用 RabbitMQ 使消费者具有弹性?

Visual Studio 2015 CTP 6 中的 C# 交互窗口