IResultFilter 不一致地写响应

IResultFilter not consistently writing response

我有以下代码:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {            
        services.AddMvc().AddMvcOptions(options =>
        {
            options.Filters.Add(new MessageAttribute("This is the Globally-Scoped Filter"));
        });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseMvcWithDefaultRoute();
    }
}

public class MessageAttribute : ResultFilterAttribute
{
    private string message;
    public MessageAttribute(string msg)
    {
        message = msg;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        WriteMessage(context, $"<div>Before Result:{message}</div>");
    }

    public override void OnResultExecuted(ResultExecutedContext context)
    {
        WriteMessage(context, $"<div>After Result:{message}</div>");
    }

    private void WriteMessage(FilterContext context, string msg)
    {
        var bytes = Encoding.ASCII.GetBytes($"<div>{msg}</div>");
        context.HttpContext.Response.Body.Write(bytes, 0, bytes.Length);
    }
}

[Message("This is the Controller-Scoped Filter", Order = 10)]
public class HomeController : Controller
{
    [Message("This is the First Action-Scoped Filter", Order = 1)]
    [Message("This is the Second Action-Scoped Filter", Order = -1)]
    public ViewResult Index()
    {
        return View("Message", $"This is the {nameof(Index)} action on the {nameof(HomeController)}");
    }
}

当我点击 Index() 操作方法时。我得到这 3 个输出之一:

1)

Before Result:This is the Second Action-Scoped Filter
Before Result:This is the Globally-Scoped Filter
Before Result:This is the First Action-Scoped Filter
Before Result:This is the Controller-Scoped Filter
After Result:This is the Controller-Scoped Filter
After Result:This is the First Action-Scoped Filter
After Result:This is the Globally-Scoped Filter
After Result:This is the Second Action-Scoped Filter
Before Result:This is the Second Action-Scoped Filter
Before Result:This is the Globally-Scoped Filter
Before Result:This is the First Action-Scoped Filter
Before Result:This is the Controller-Scoped Filter

空白页

页面加载时,通常为 2),但有时为 3)。刷新后它有时会给我 1),但不断刷新页面会给我随机结果,有利于 2) 和 3)。

如果我在 WriteMessage() 中放置一个断点,让它中断,然后继续执行,它会给出预期的 1) 输出。

为什么会出现这种不一致的行为?

来自 Pro ASP.NET Core MVC 2 的作者 Adam Freeman,我从中获得了代码片段:

In 2.0, responses were not written until all of the components in the pipeline have processed the request. In 2.1, that changed so that the response is written as soon as content is produced. When you try to add to the body, ASP.NET Core gets confused because it needs to update the Content-Length header but can't because the response is being written out already.

The inconsistent results appear because you have created a race condition. Sometimes your filters get to modify the response before a thread is allocated to write it out, sometimes not. You can either use the version of ASP.NET Core specified in the book or update your code so that it doesn't try to modify the response after the action method renders its view.