【问题标题】:ASP.NET Core modify/substitute request bodyASP.NET Core 修改/替换请求正文
【发布时间】:2017-11-13 21:24:58
【问题描述】:

我想对 HttpContext.Request.Body 进行替换。

我已经尝试在中间件中做到这一点:

public async Task Invoke(HttpContext context)
{
    if (context.Request.Path.Value.Contains("DataSourceResult"))
    {
        var originalBody = new StreamReader(context.Request.Body).ReadToEnd();
        DataSourceRequest dataSource = null;

        try
        {
            dataSource = JsonConvert.DeserializeObject<DataSourceRequest>(originalBody);
        } catch
        {
            await _next.Invoke(context);
        }

        if (dataSource != null && dataSource.Take > 2000)
        {
            dataSource.Take = 2000;

            var bytesToWrite = dataSource.AsByteArray();
            await context.Request.Body.WriteAsync(bytesToWrite, 0, bytesToWrite.Length);
        }
        else
        {
            var bytesToWrite = originalBody.AsByteArray();
            await context.Request.Body.WriteAsync(bytesToWrite, 0, bytesToWrite.Length);
        }
    }

    await _next.Invoke(context);
}

第一个问题是body只能读取一次,其次stream是只读的,不能写入。

如何修改/替换Request.Body?我需要更改请求正文的属性值。

【问题讨论】:

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


    【解决方案1】:

    获取请求正文,读取其内容,进行必要的更改(如果有的话),然后创建一个新流以沿管道传递。一旦访问,请求流必须被替换。

    public async Task Invoke(HttpContext context) {
        var request = context.Request;
        if (request.Path.Value.Contains("DataSourceResult")) {
            //get the request body and put it back for the downstream items to read
            var stream = request.Body;// currently holds the original stream                    
            var originalContent = new StreamReader(stream).ReadToEnd();
            var notModified = true;
            try {
                var dataSource = JsonConvert.DeserializeObject<DataSourceRequest>(originalContent);
                if (dataSource != null && dataSource.Take > 2000) {
                    dataSource.Take = 2000;
                    var json = JsonConvert.SerializeObject(dataSource);
                    //replace request stream to downstream handlers
                    var requestContent = new StringContent(json, Encoding.UTF8, "application/json");
                    stream = await requestContent.ReadAsStreamAsync();//modified stream
                    notModified = false;
                }
            } catch {
                //No-op or log error
            }
            if (notModified) {
                //put original data back for the downstream to read
                var requestData = Encoding.UTF8.GetBytes(originalContent);
                stream = new MemoryStream(requestData);
            }
    
            request.Body = stream;
        }
        await _next.Invoke(context);
    }
    

    【讨论】:

    • 我们不是也需要修改Request.ContentLength吗?我们需要Dispose()原来的Request.Body吗?
    • @Pang 从流中提取内容长度。无需手动更改。由于中间件管道的设计方式的性质,不建议将其丢弃,因为它可能会影响链/管道中的其他中间件。
    • 为什么需要if (notModified) { 块。如果notModifiedtruerequest.Body 将保持不变,不是吗?
    • @SateeshPagolu 因为之前的代码块可能会修改流,所以将notModified 更改为false。阅读代码中的 cmets。
    【解决方案2】:

    就我而言,还需要将 Request.ContentLength 更新为新值。 我的解决方案是:

    string originalContent;
    using (StreamReader stream = new StreamReader(context.Request.Body))
    {
        originalContent = stream.ReadToEnd();
    }
    
    var dataSource = JsonConvert.DeserializeObject<DataSourceRequest>(originalContent);
    if (dataSource != null && dataSource.Take > 2000)
        dataSource.Take = 2000;
    
    string json = JsonConvert.SerializeObject(dataSource);
    var requestData = Encoding.UTF8.GetBytes(json);
    context.Request.Body = new MemoryStream(requestData);
    context.Request.ContentLength = context.Request.Body.Length;
    

    【讨论】:

      猜你喜欢
      • 2019-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-03
      相关资源
      最近更新 更多