#c# #asp.net-core-2.1
#c# #asp.net-core-2.1
Вопрос:
У меня есть следующий код:
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).
Почему происходит такое непоследовательное поведение?
Комментарии:
1. Возможно, вам потребуется очистить () буфер сообщений. Таймеры используются в потоках для перемещения данных из временного буфера на вывод.
2. Я не могу воспроизвести это (хотя я использую .NET Core 3.1). Я бы предложил использовать асинхронную версию этого кода, хотя. Так что переопределите
OnResultExecutionAsync
и используйтеcontext.HttpContext.Response.Body.WriteAsync
Ответ №1:
От Адама Фримена, автора Pro ASP.NET Ядро MVC 2, откуда я получил фрагменты кода:
В версии 2.0 ответы не записывались до тех пор, пока все компоненты в конвейере не обработают запрос. В версии 2.1 это изменилось таким образом, что ответ записывается сразу после создания содержимого. Когда вы пытаетесь добавить в тело, ASP.NET Ядро запутывается, потому что ему нужно обновить заголовок Content-Length, но он не может, потому что ответ уже записывается.
Противоречивые результаты появляются, потому что вы создали условие гонки. Иногда ваши фильтры могут изменять ответ до того, как поток будет выделен для его записи, иногда нет. Вы можете либо использовать версию ASP.NET Ядро, указанное в книге, или обновите свой код, чтобы он не пытался изменить ответ после того, как метод действия отобразит его представление.
Комментарии:
1. Похоже, что обновление — это правильный подход, потому что это прямая ошибка
2. @AluanHaddad ты имеешь в виду понижение рейтинга? Я получаю эту ошибку, потому что я использую 2.1 вместо 2.0.