本文介绍了访问原始请求正文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图访问ASP.net 5中请求的原始输入正文/流.过去,我能够将输入流的位置重置为0并将其读入内存流,但是当我尝试要从上下文中做到这一点,输入流为null或抛出错误(System.NotSupportedException =>不支持指定的方法.").

I'm trying to access a request's raw input body/stream in ASP.net 5. In the past, I was able to reset the position of the input stream to 0 and read it into a memory stream but when I attempt to do this from the context the input stream is either null or throws an error (System.NotSupportedException => "Specified method is not supported.").

在下面的第一个示例中,如果我将控制器方法的参数对象类型声明为动态的,则可以访问控制器中的原始请求.由于各种原因,这不是解决方案,无论如何,我仍然需要在身份验证过滤器中访问原始请求正文.

In the first example below I can access the raw request in a controller if I declare the controller method's parameter object type as dynamic. For various reasons, this is not a solution and I need to access the raw request body in an authentication filter anyways.

此示例有效,但不是合理的解决方案:

This Example Works, But Is Not a Reasonable Solution:

[HttpPost("requestme")]
public string GetRequestBody([FromBody] dynamic body)
{
    return body.ToString();
}

抛出错误:

[HttpPost("requestme")]
public string GetRequestBody()
{
    var m = new MemoryStream();
    Request.Body.CopyTo(m);

    var contentLength = m.Length;

    var b = System.Text.Encoding.UTF8.GetString(m.ToArray());

    return b;
}

抛出错误:

[HttpPost("requestme")]
public string GetRequestBody()
{
    Request.Body.Position = 0;
    var input = new StreamReader(Request.Body).ReadToEnd();

    return input;
}

抛出错误:

[HttpPost("requestme")]
public string GetRequestBody()
{
    Request.Body.Position = 0;
    var input = new MemoryStream();
    Request.Body.CopyTo(input);

    var inputString = System.Text.Encoding.UTF8.GetString(input.ToArray());

    return inputString;
}

我需要访问要构建的API的每个请求的原始请求正文.

I need to access the raw request body of every request that comes in for an API that I am building.

任何帮助或指导将不胜感激!

Any help or direction would be greatly appreciated!

这是我想在其中读取请求正文的代码.

Here is the code that I would like to read the request body in.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Http;

namespace API.Filters
{
    public class CustomAuthorizationAttribute : Attribute, IAuthorizationFilter
    {
        public CustomAuthorizationAttribute()
        { }

        public void OnAuthorization(AuthorizationContext context)
        {
            if (context == null)
                throw new ArgumentNullException("OnAuthorization AuthorizationContext context can not be null.");
            else
            {
                if (this.AuthorizeCore(context.HttpContext) == false)
                {
                    // Do Other Stuff To Check Auth
                }
                else
                {
                    context.Result = new HttpUnauthorizedResult();
                }
            }
        }

        protected virtual bool AuthorizeCore(HttpContext httpContext)
        {
            var result = false;

            using (System.IO.MemoryStream m = new System.IO.MemoryStream())
            {
                try
                {
                    if (httpContext.Request.Body.CanSeek == true)
                        httpContext.Request.Body.Position = 0;

                    httpContext.Request.Body.CopyTo(m);

                    var bodyString = System.Text.Encoding.UTF8.GetString(m.ToArray());

                    return CheckBody(bodyString); // Initial Auth Check returns true/false <-- Not Shown In Code Here on Stack Overflow
                }
                catch (Exception ex)
                {
                    Logger.WriteLine(ex.Message);
                }
            }
                return false;
        }
    }
}

当这样调用标有CustomAuthorization属性的控制器方法时,将访问此代码.

This code would be accessed when a call is made to a controller method marked with the CustomAuthorization attribute like so.

[Filters.CustomAuthorizationAuthorization]
[HttpPost]
public ActionResult Post([FromBody]UserModel Profile)
{
    // Process Profile
}

推荐答案

Request.Body的实现取决于控制器的操作.

The implementation of Request.Body depends on the controller action.

如果操作包含参数,则由Microsoft.AspNet.WebUtilities.FileBufferingReadStream实现,该功能支持查找(Request.Body.CanSeek == true).此类型还支持设置Request.Body.Position.

If the action contains parameters it's implemented by Microsoft.AspNet.WebUtilities.FileBufferingReadStream, which supports seeking (Request.Body.CanSeek == true). This type also supports setting the Request.Body.Position.

但是,如果您的操作不包含任何参数,则由Microsoft.AspNet.Loader.IIS.FeatureModel.RequestBody实现,不支持搜索(Request.Body.CanSeek == false).这意味着您无法调整Position属性,而只能开始阅读流.

However, if your action contains no parameters it's implemented by Microsoft.AspNet.Loader.IIS.FeatureModel.RequestBody, which does not support seeking (Request.Body.CanSeek == false). This means you can not adjust the Position property and you can just start reading the stream.

这种差异可能与MVC需要从请求主体中提取参数值有关,因此它需要读取请求.

This difference probably has to do with the fact that MVC needs to extract the parameters values from the request body, therefore it needs to read the request.

在您的情况下,您的操作没有任何参数.因此,使用Microsoft.AspNet.Loader.IIS.FeatureModel.RequestBody,如果尝试设置Position属性,则会引发异常.

In your case, your action does not have any parameters. So the Microsoft.AspNet.Loader.IIS.FeatureModel.RequestBody is used, which throws an exception if you try to set the Position property.


解决方案:要么不设置位置,要么检查您是否真的可以首先设置位置:


Solution: either do not set the position or check if you actually can set the position first:

if (Request.Body.CanSeek)
{
    // Reset the position to zero to read from the beginning.
    Request.Body.Position = 0;
}

var input = new StreamReader(Request.Body).ReadToEnd();

这篇关于访问原始请求正文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 18:16