【问题标题】:Wanting ASP.NET Core Middleware to run after MVC Razor View Engine希望 ASP.NET Core 中间件在 MVC Razor 视图引擎之后运行
【发布时间】:2017-03-27 17:04:00
【问题描述】:

在 MVC Razor 视图引擎处理数据后,我希望在 ASP.NET Core 中运行 MiddleWare 模块。我可以让它运行,但它似乎没有收集到所有数据。我有一个更新 DI 对象集合的 Tag Helper,但是当中间件运行时,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


    【解决方案1】:

    据我所知,在请求管道中的 mvc 之后无法运行中间件。如果要操作剃刀输出,可以使用过滤器。结果过滤器似乎适合您的情况。

    结果过滤器非常适合需要直接包围的任何逻辑 查看执行或格式化程序执行。结果过滤器可以替换或 修改负责产生 回应。

    见官方文档https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters#result-filters

    另请参阅如何通过过滤器使用依赖注入 https://docs.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);
                            }
                        }
                }
            }
        }
    }
    

    【讨论】:

    • 嗨@ademcaglin,谢谢。我已经编写了一个 OnResultExecuted 过滤器,但我没有在我的 htmlData 中获取已处理的剃须刀 html(我得到的是空字符串)。如何编写一个动作过滤器来捕获和更新 razor 处理的 html?我不清楚过滤器在哪里执行以及如何将我的过滤器放在我可以捕获 html 并更新它的地方。我已经通过问题更新了“可能但不起作用的过滤器代码”。
    • 你是对的。似乎它不适用于剃须刀输出。但是我找到了中间件方法的解决方案,它按预期工作。查看我的更新。
    猜你喜欢
    • 2011-03-11
    • 1970-01-01
    • 2012-06-24
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多