ActionFilterAttribute 或 IActionFilter 中的 HttpResponseBody 操作或替换

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

就这么简单,我试图用另一个流替换我的 context.HttpContext.Response.Body 。

我已经走了这么远,我可以劫持流,但替换它不起作用。现在我在这个例子中使用了 Weatherforecast web-api 模板。

public override void OnResultExecuted(ResultExecutedContext context)
    {
        responseBody.Seek(0, SeekOrigin.Begin);
        var originalBody = context.HttpContext.Response.Body;
        using var sr = new StreamReader(responseBody);
        var actionResult = sr.ReadToEnd();

        using var memStream = new MemoryStream();
        context.HttpContext.Response.Body = memStream;
        var fake = actionResult.Replace("Warm", "REPLACED", StringComparison.InvariantCultureIgnoreCase).Replace("Hot", "REPLACED", StringComparison.InvariantCultureIgnoreCase);

        memStream.Position = 0;
        var data = GetStreamWithGetBytes(fake, Encoding.UTF8);
        memStream.Write(data, 0, data.Length);

        memStream.Position = 0;
        memStream.CopyToAsync(originalBody);

        context.HttpContext.Response.Body = originalBody;

    }

如您所见,我正在用 REPLACED 替换“温暖”或“热”

替换工作正常,但是分配更改的数据并将其读入流中并返回上下文。HttpContext.Response.Body 似乎不起作用。

请问我错过了什么?

我不是在寻找中间件解决方案。我想用我的自定义动作过滤器来装饰我们的控制器。所以必须用actionfilterattribute或者IActionFilter来实现。

完整代码如下:

public class MessageFilter : ActionFilterAttribute
{
    private MemoryStream responseBody;

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        //context.HttpContext.Request.EnableBuffering();
        this.responseBody = new MemoryStream();
        //hijack the real stream with our own memory stream
        context.HttpContext.Response.Body = responseBody;
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        
    }

    public override void OnResultExecuted(ResultExecutedContext context)
    {
        responseBody.Seek(0, SeekOrigin.Begin);
        var originalBody = context.HttpContext.Response.Body;
        using var sr = new StreamReader(responseBody);
        var actionResult = sr.ReadToEnd();

        using var memStream = new MemoryStream();
        context.HttpContext.Response.Body = memStream;
        var fake = actionResult.Replace("Warm", "REPLACED", StringComparison.InvariantCultureIgnoreCase).Replace("Hot", "REPLACED", StringComparison.InvariantCultureIgnoreCase);

        memStream.Position = 0;
        var data = GetStreamWithGetBytes(fake, Encoding.UTF8);
        memStream.Write(data, 0, data.Length);

        memStream.Position = 0;
        memStream.CopyToAsync(originalBody);

        context.HttpContext.Response.Body = originalBody;

    }

    public static byte[] GetStreamWithGetBytes(string sampleString, Encoding? encoding = null)
    {
        encoding ??= Encoding.UTF8;
        var byteArray = encoding.GetBytes(sampleString);
        return byteArray;
    }
}

控制器类:

using Microsoft.AspNetCore.Mvc;
using WebApplicationHttpMessageHandler.Filters;

namespace WebApplicationHttpMessageHandler.Controllers;

[ApiController]
[Route("[controller]/[action]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet(Name = "GetWeatherForecast")]
    [ServiceFilter(typeof(MessageFilter))]
    public IEnumerable<WeatherForecast> Get()
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

我真的被困在这里了。

c# asp.net-web-api action-filter actionfilterattribute
1个回答
0
投票

更改

MessageFilter
如下:

using Microsoft.AspNetCore.Mvc.Filters;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;

public class MessageFilter : ActionFilterAttribute
{
    public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        if (context.Result is not ObjectResult result)
        {
            await base.OnResultExecutionAsync(context, next);
            return;
        }

        var data = JsonSerializer.Serialize(result.Value);
        var fake = data.Replace("Warm", "REPLACED", StringComparison.InvariantCultureIgnoreCase).Replace("Hot", "REPLACED", StringComparison.InvariantCultureIgnoreCase);
        context.HttpContext.Response.ContentType = "application/json";
        await context.HttpContext.Response.WriteAsync(fake);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.