在asp.net核心响应之前和之后附加自定义HTML输出? [英] Append Custom HTML output before and after response in asp.net core?

查看:9
本文介绍了在asp.net核心响应之前和之后附加自定义HTML输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 .net 核心应用程序,可以发出 API 输出.

我的Configure 方法非常简单:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env ){如果 (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints => { endpoints.MapControllers(); });}

这是 API 的当前输出:

仅出于测试目的,我想在响应前后添加 HTML 标记:

类似(在 DOM 中手动编辑):

所以我添加了这个:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env ){app.Use(async (context, next) =>{await context.Response.WriteAsync("<b> Hi</b>");等待下一个();await context.Response.WriteAsync("<b>再见</b>");});如果 (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints => { endpoints.MapControllers(); });}

但是当我运行它时,我得到:

<块引用>

失败:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware

我一直在 SO 中寻找解决方案,但没有找到,该怎么做.

问题:

为什么会这样?我以为我可以通过在管道上调用 next() 来控制管道并做任何我想做的事情.

如何在前后添加自定义 HTML 标签?

如果我将代码移到 Configure 方法的末尾,我会看到 常规输出,没有异常,但没有HTML标签.

编辑 #2:

我也尝试过 OnStarting 事件,但仍然没有成功(我得到一个空页面):

 app.Use(async (context, next) =>{context.Response.OnStarting(异步状态=>{如果(状态是 HttpContext httpContext){var request = httpContext.Request;var response = httpContext.Response;等待响应 .WriteAsync("<b>再见</b>");//<----}}, 语境);等待下一个();});

解决方案

好的,我想我有!正如你所研究的那样,这是极具挑战性的……我所做的方法是编写一个自定义的 IOutputFormatter.

//在 ConfigureServices() 中services.AddControllers(opt =>{opt.OutputFormatters.Clear();opt.OutputFormatters.Add(new AppendHtmlOutputFormatter());});//格式化类公共类 AppendHtmlOutputFormatter : IOutputFormatter{public bool CanWriteResult(OutputFormatterCanWriteContext context) =>真的;//如果您不想一直追加,请在此处添加一些逻辑公共任务 WriteAsync(OutputFormatterWriteContext 上下文){var json = System.Text.Json.JsonSerializer.Serialize(context.Object);var modified =<b>Hi!</b>";+ json + "<b>再见!</b>";返回 context.HttpContext.Response.WriteAsync(已修改);}}

现在,当我运行 API 端点时,我得到以下响应:

<b>嗨!</b>{Bar":42}<b>再见!</b>

这就是你要找的吗?

默认输出格式化程序

请注意,.Clear() 会删除以下默认的 OutputFormatters - 按此顺序:

  1. HttpNoContentFormatter
  2. StringOutputFormatter
  3. StreamOutputFormatter
  4. SystemTextJsonOutputFormatter

上面的解决方案替换了所有这些,并使用 AppendHtmlOutputFormatter 来处理所有内容.因此,以下可能是首选选项(尽管不会将 HTML 输出附加到所有内容):

//在 ConfigureServices() 中services.AddControllers(opt =>{opt.OutputFormatters.Clear();opt.OutputFormatters.Add(new HttpNoContentOutputFormatter());opt.OutputFormatters.Add(new StreamOutputFormatter());opt.OutputFormatters.Add(new AppendHtmlOutputFormatter());});

替代.Clear()

如果您不删除默认格式化程序,.NET 将使用它们并且永远不会到达自定义格式化程序.但是,如果您不想删除所有格式化程序(例如,另一项功能正在添加它们),您也可以按类型一次删除一个:

services.AddControllers(opt =>{opt.OutputFormatters.RemoveType();opt.OutputFormatters.RemoveType();opt.OutputFormatters.Add(new AppendHtmlOutputFormatter());});

I have a simple .net core app that emits an API output.

My Configure method is pretty simple :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env  )
        {

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
    }

This is the current output from the API :

Just for testing purpose, I want to add HTML tag before and after the response :

Something like ( edited manually in DOM ) :

So I've added this :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env  )
        {
            

          app.Use(async (context, next) =>
         {
             await context.Response.WriteAsync("<b> Hi</b>");
             await next ();
             await context.Response.WriteAsync("<b> Bye </b>");
         });




            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
    }

But when I run it , I get :

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware1 An unhandled exception has occurred while executing the request. System.InvalidOperationException: Headers are read-only, response has already started. With this HTML :

I've been searching for a solution in SO but didn't find, how to do it.

Question:

Why is it happening? I thought I can control the pipeline and do whatever I want it via calling next() on the pipeline.

How can I add my custom HTML tags before and after?

Edit:

If I move the code to the end of the Configure method, I see the regular output , without getting the exception, but without the HTML tags.

Edit #2 :

I've also tried with OnStarting event , but still , no success (I get an empty page):

 app.Use(async (context, next) =>
        {
          
            context.Response.OnStarting(async state =>
            {
                if (state is HttpContext httpContext)
                {
                    var request = httpContext.Request;
                    var response = httpContext.Response;
                    await response .WriteAsync("<b> Bye </b>"); // <----
               }
            }, context);
            await next();
             
        });

解决方案

OK, I think I have it! It's extremely challenging as you've worked out... the way I've done it is by writing a custom IOutputFormatter.

// in ConfigureServices()
services.AddControllers(opt =>
{
    opt.OutputFormatters.Clear();
    opt.OutputFormatters.Add(new AppendHtmlOutputFormatter());
});

// Formatter class
public class AppendHtmlOutputFormatter : IOutputFormatter
{
    public bool CanWriteResult(OutputFormatterCanWriteContext context) =>
        true; // add some logic here if you don't want to append all the time

    public Task WriteAsync(OutputFormatterWriteContext context)
    {
        var json = System.Text.Json.JsonSerializer.Serialize(context.Object);

        var modified = "<b>Hi!</b>" + json + "<b>Bye!</b>";
        return context.HttpContext.Response.WriteAsync(modified);
    }
}

Now when I run an API endpoint I get the following response:

<b>Hi!</b>{"Bar":42}<b>Bye!</b>

Is that what you're looking for?

Default Output Formatters

Be aware that the following default OutputFormatters are removed by .Clear() - in this order:

  1. HttpNoContentFormatter
  2. StringOutputFormatter
  3. StreamOutputFormatter
  4. SystemTextJsonOutputFormatter

The solution above replaces all these and uses AppendHtmlOutputFormatter for everything. Therefore the following may be a preferred option (though won't append the HTML output to everything):

// in ConfigureServices()
services.AddControllers(opt =>
{
    opt.OutputFormatters.Clear();
    opt.OutputFormatters.Add(new HttpNoContentOutputFormatter());
    opt.OutputFormatters.Add(new StreamOutputFormatter());
    opt.OutputFormatters.Add(new AppendHtmlOutputFormatter());
});

Alternative to .Clear()

If you don't remove the default formatters, .NET will use those and never reach the custom formatter. However, if you prefer not to remove all formatters (e.g. another feature is adding them in), you can also remove them one at a time by type:

services.AddControllers(opt =>
{
    opt.OutputFormatters.RemoveType<StringOutputFormatter>();
    opt.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
    opt.OutputFormatters.Add(new AppendHtmlOutputFormatter());
});

这篇关于在asp.net核心响应之前和之后附加自定义HTML输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆