【问题标题】:Inject a script reference in HTML files using ASP.NET Core middleware使用 ASP.NET Core 中间件在 HTML 文件中注入脚本引用
【发布时间】:2019-02-28 21:22:24
【问题描述】:

我正在尝试使用中间件将脚本引用注入到由 ASP.NET Core 应用程序生成的所有 HTML 中。我的代码受到this blog 帖子的启发,看起来像这样:

public class MyMiddleware
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        var newContent = string.Empty;
        var existingBody = context.Response.Body;

        using (var newBody = new MemoryStream())
        {
            context.Response.Body = newBody;

            try
            {
                await _next.Invoke(context);
            }
            finally
            {
                context.Response.Body = existingBody;
            }

            newBody.Seek(0, SeekOrigin.Begin);

            newContent = new StreamReader(newBody).ReadToEnd();

            if (context.Response.ContentType.StartsWith("text/html"))
            {
                newContent = newContent.Replace("</body", "<script src=\"my-reference-here\"></script></body");
            }

            await context.Response.WriteAsync(newContent);
        }
    }
}

这里的主要挑战是中间件运行对服务器的所有请求,包括 CSS、javascript、favicon 等。我希望它只运行 HTML 输出,因为上面的代码会导致某些文件类型和问题因为我不想把所有的回复都写两次。

有什么更好的方法吗?我已经登录MapWhen,但它似乎不支持查看响应的内容类型。

【问题讨论】:

    标签: asp.net-core asp.net-core-middleware


    【解决方案1】:

    我个人会建议您将其作为中间件来实现。从您自己的实现中可以看出,您将整个响应读入内存只是为了能够对其执行一些替换。这确实效率低下,并且会阻止您流式传输响应。 BrowserLinkmodifying the stream as it happens 执行此操作,这样会更有效。

    但是您应该考虑将这个逻辑移到 MVC 中。当然,这假设您不需要修改静态文件内容。但是在 MVC 中,您可以编写一个 result filter,它仅在生成 ViewResult 时(即渲染 MVC 视图时)才会执行。然后在该过滤器中,您可以修改视图结果以设置一些参数来注入该脚本。

    在 MVC 内部,我只需在您的布局中添加一个标签助手或某个部分,然后您可以在其中呈现您的脚本标签。这样一来,您就可以完全控制布局并将其与 MVC 很好地集成。

    话虽如此,为避免为不相关的响应运行中间件,当然您也可以简单地将您对 Response.ContentType 的检查移动到更远的位置,这样您实际上不会将响应读入内存流中以获取您所做的响应不需要修改。

    【讨论】:

    • 你是对的。通过中间件注入脚本可能会出错,并且正如您提到的那样效率低下。我已经实现了一个插入脚本的标签助手。它需要一些手工工作,但我相信这是值得的。谢谢!
    【解决方案2】:

    我建议在您的视图中使用部分。只需在您的布局中实现它:

    @RenderSection("BottomScripts", required: false)
    

    然后在你的视图中你可以使用这样的东西:

    @section BottomScripts {
     @if (Model.NeedThisScript)
     {
      await Html.RenderPartialAsync("PartialWithYourScripts");
     }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-11-05
      • 2021-04-26
      • 2018-08-27
      • 2013-11-30
      • 1970-01-01
      • 1970-01-01
      • 2013-11-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多