我有一个服务器大小的 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.HasStarted
为true,并且调用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.HasStarted
为 true,这就是抛出错误的原因。您需要做的是在响应开始之前对 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/