我希望在 MVC Razor View Engine 处理数据后在 ASP.NET Core 中运行中间件模块。 我可以让它运行,但它似乎没有收集所有数据。 我有一个标记帮助程序,可以更新 DI 对象的集合,但是当中间件运行时,DI 对象的集合为空。 我的startup.cs看起来像这样:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMiddleware<MyMiddleware>();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
我的中间件是这样的:
public class MyMiddleware
{
private readonly RequestDelegate nextMiddleware;
private readonly IScriptManager _scriptManager;
public MyMiddleware(RequestDelegate next, IScriptManager scriptManager)
{
this.nextMiddleware = next;
_scriptManager = scriptManager;
}
public async Task Invoke(HttpContext context)
{
var cnt = _scriptManager.ScriptTexts.Count;
.. get HTML
Stream originalStream = context.Response.Body;
...
.. update HTML
await context.Response.WriteAsync(htmlData);
我确实得到了我想要的 HTML,但我的 DI 中的集合似乎没有更新。
*** 注释 - 可能但不起作用的结果过滤器
services.AddMvc(options =>
{
options.Filters.Add(new AppendToHtmlBodyFilter());
});
public class AppendToHtmlBodyFilter : TypeFilterAttribute
{
private readonly IScriptManager _scriptManager;
public AppendToHtmlBodyFilter():base(typeof(SampleActionFilterImpl))
{
}
private class SampleActionFilterImpl : IResultFilter
{
private readonly IScriptManager _scriptManager;
public SampleActionFilterImpl(IScriptManager scriptManager)
{
_scriptManager = scriptManager;
//_logger = loggerFactory.CreateLogger<SampleActionFilterAttribute>();
}
public void OnResultExecuted(ResultExecutedContext context)
{
var cnt = _scriptManager.ScriptTexts.Count;
Stream originalStream = context.HttpContext.Response.Body;
using (MemoryStream newStream = new MemoryStream())
{
context.HttpContext.Response.Body = newStream;
context.HttpContext.Response.Body = originalStream;
newStream.Seek(0, SeekOrigin.Begin);
StreamReader reader = new StreamReader(newStream);
var htmlData = reader.ReadToEnd();
据我所知,在请求管道中的 mvc 之后无法运行中间件。如果您想操纵剃刀输出,可以使用过滤器。结果过滤器似乎适合您的情况。
结果过滤器非常适合任何需要直接包围的逻辑 查看执行或格式化程序执行。结果过滤器可以替换或 修改负责产生的操作结果 回应。
参见官方文档https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters#result-filters
另请参阅如何使用过滤器进行依赖注入https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters#dependency-injection
更新
我无法让它与结果过滤器一起工作(它可以工作 json 结果,但不能工作 viewresult)。
但是我发现了一个很好的中间件示例:http://www.mikesdotnetting.com/article/269/asp-net-5-middleware-or-where-has-my-httpmodule-gone
public class MyMiddleware
{
private readonly RequestDelegate nextMiddleware;
private readonly IScriptManager _scriptManager;
public MyMiddleware(RequestDelegate next, IScriptManager scriptManager)
{
this.nextMiddleware = next;
_scriptManager = scriptManager;
}
public async Task Invoke(HttpContext context)
{
var cnt = _scriptManager.ScriptTexts.Count;
using (var memoryStream = new MemoryStream())
{
var bodyStream = context.Response.Body;
context.Response.Body = memoryStream;
await _next(context);
var isHtml = context.Response.ContentType?.ToLower().Contains("text/html");
if (context.Response.StatusCode == 200 && isHtml.GetValueOrDefault())
{
memoryStream.Seek(0, SeekOrigin.Begin);
using (var streamReader = new StreamReader(memoryStream))
{
var responseBody = await streamReader.ReadToEndAsync();
// update html
using (var amendedBody = new MemoryStream())
using (var streamWriter = new StreamWriter(amendedBody))
{
streamWriter.Write(responseBody);
amendedBody.Seek(0, SeekOrigin.Begin);
await amendedBody.CopyToAsync(bodyStream);
}
}
}
}
}
}
对于其他遇到此问题想知道如何做到这一点的人。您可以通过在中间件的
nextMiddleware
方法中的代码之前调用 InvokeAsync
来完成此操作。
public class MyMiddleware
{
private readonly RequestDelegate nextMiddleware;
private readonly IScriptManager _scriptManager;
public MyMiddleware(RequestDelegate next, IScriptManager scriptManager)
{
this.nextMiddleware = next;
_scriptManager = scriptManager;
}
public async Task InvokeAsync(HttpContext context)
{
await nextMiddleware(context);
var cnt = _scriptManager.ScriptTexts.Count;
.. get HTML
Stream originalStream = context.Response.Body;
...
.. update HTML
await context.Response.WriteAsync(htmlData);
}
}