希望 ASP.NET Core 中间件在 MVC Razor View Engine 之后运行

问题描述 投票:0回答:2

我希望在 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();
asp.net-core asp.net-core-middleware
2个回答
4
投票

据我所知,在请求管道中的 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);
                        }
                    }
            }
        }
    }
}

0
投票

对于其他遇到此问题想知道如何做到这一点的人。您可以通过在中间件的

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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.