响应开始后无法建立会话

时间:2016-12-12 20:44:51

标签: c# session asp.net-core asp.net-core-mvc

我在日志中看到了这个错误,但我无法弄清楚如何重现它。它不会定期发生。

异常消息:响应开始后无法建立会话。 堆栈跟踪:

at Microsoft.AspNetCore.Session.DistributedSession.Set(String key,Byte [] value)

CustomMiddleware.cs:

    public async Task Invoke(HttpContext context, AlertWriter alertWriter, AlertReader alertReader)
    {
        var sessionAlerts = context.Session.GetString(AlertKey);

        if (!string.IsNullOrWhiteSpace(sessionAlerts))
        {
            var alerts = JsonConvert.DeserializeObject<List<Alert>>(sessionAlerts);
            alertReader.Initialize(alerts);

            context.Session.Remove(AlertKey);
        }

        await _next.Invoke(context);

        if (context.Response.StatusCode >= 300 && context.Response.StatusCode < 400)
        {
            alertWriter.Alerts = alertWriter.Alerts.Union(alertReader).ToList();
        }

        var serializedAlerts = JsonConvert.SerializeObject(alertWriter.Alerts);

        //ERROR IS HERE
        context.Session.SetString(AlertKey, serializedAlerts);
    }

在Startup.cs中,app.UseSession();是第一个app.Use ...我打电话。 Documentation表示如果&#34;在您已经开始写入响应流后,尝试创建新的会话(即尚未创建会话cookie),则会发生此错误&#34; < / em>的

如何避免此错误?似乎如果我尝试在任何自定义中间件中访问会话,我将不得不检查.AspNetCore.Session cookie是否存在?

1 个答案:

答案 0 :(得分:1)

您必须在发送内容之前设置标头。

await _next.Invoke(..)之前执行此操作通常是安全的。但是在_next之后调用它之后,无法保证在链中稍后调用的中间件确实或者没有写入流。

您可以通过缓存响应来绕过它,直到您的中间件完成,但这可能会产生严重的性能影响,因为整个流需要存储在内存中,然后再存储在写入原始流的后续中间件中。在大响应中,这可能会显着增加应用程序的内存使用量。

这样的东西
using (var buffer = new MemoryStream())
{
    var body = context.Response.Body;
    context.Response.Body = buffer;
    ...
    await _next.Invoke(...);

    // set headers or session
    context.Session.SetString(AlertKey, serializedAlerts);

    // read buffer and write to body
}