【问题标题】:How to read request body in an asp.net core webapi controller?如何在 asp.net 核心 webapi 控制器中读取请求正文?
【发布时间】:2017-03-22 13:14:24
【问题描述】:

我试图在 OnActionExecuting 方法中读取请求正文,但我总是得到 null 的正文。

var request = context.HttpContext.Request;
var stream = new StreamReader(request.Body);
var body = stream.ReadToEnd();

我尝试将流位置显式设置为 0,但这也不起作用。由于这是 ASP.NET Core,所以我认为情况有些不同。我可以在此处看到所有示例都指的是旧的 Web API 版本。

还有其他方法吗?

【问题讨论】:

  • 请注意,如果之前在请求管道期间已经读取了请求正文,那么当您尝试第二次读取时它是空的
  • @Fabio 感谢您的信息,我们可以设置位置并再次阅读吗?
  • @KasunKoswattha - 按照设计,正文内容被视为只能读取一次的只进流。
  • 我猜这个问题是针对过滤器或中间件而不是控制器。

标签: c# asp.net-web-api asp.net-core


【解决方案1】:

在 ASP.Net Core 中,多次读取正文请求似乎很复杂,但是如果您的第一次尝试以正确的方式进行,那么接下来的尝试应该没问题。

我阅读了几个转变,例如通过替换正文流,但我认为以下是最干净的:

最重要的一点是

  1. 让请求知道您将读取其正文两次或更多次,
  2. 不关闭正文流,并且
  3. 将其倒回其初始位置,以免内部进程丢失。

[编辑]

正如 Murad 所指出的,您还可以利用 .Net Core 2.1 扩展:EnableBuffering 它将大请求存储到磁盘上,而不是将其保存在内存中,避免存储在内存中的大流问题(文件、图片, ...)。 您可以通过设置ASPNETCORE_TEMP环境变量来更改临时文件夹,请求结束后文件将被删除。

在 AuthorizationFilter 中,您可以执行以下操作:

// Helper to enable request stream rewinds
using Microsoft.AspNetCore.Http.Internal;
[...]
public class EnableBodyRewind : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var bodyStr = "";
        var req = context.HttpContext.Request;

        // Allows using several time the stream in ASP.Net Core
        req.EnableRewind(); 

        // Arguments: Stream, Encoding, detect encoding, buffer size 
        // AND, the most important: keep stream opened
        using (StreamReader reader 
                  = new StreamReader(req.Body, Encoding.UTF8, true, 1024, true))
        {
            bodyStr = reader.ReadToEnd();
        }

        // Rewind, so the core is not lost when it looks the body for the request
        req.Body.Position = 0;

        // Do whatever work with bodyStr here

    }
}



public class SomeController : Controller
{
    [HttpPost("MyRoute")]
    [EnableBodyRewind]
    public IActionResult SomeAction([FromBody]MyPostModel model )
    {
        // play the body string again
    }
}

然后您可以在请求处理程序中再次使用正文。

在您的情况下,如果您得到空结果,则可能意味着正文已在较早阶段被读取。在这种情况下,您可能需要使用中间件(见下文)。

但是,如果您处理大型流,则要小心,该行为意味着所有内容都已加载到内存中,这不应在文件上传的情况下触发。

您可能希望将其用作中间件

我的看起来像这样(同样,如果你下载/上传大文件,应该禁用它以避免内存问题):

public sealed class BodyRewindMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext context)
    {
        try { context.Request.EnableRewind(); } catch { }
        await _next(context);
        // context.Request.Body.Dipose() might be added to release memory, not tested
    }
}
public static class BodyRewindExtensions
{
    public static IApplicationBuilder EnableRequestBodyRewind(this IApplicationBuilder app)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        return app.UseMiddleware<BodyRewindMiddleware>();
    }

}

【讨论】:

  • 即使我倒退到位置 0,流仍然是空的。
  • 你用过req.EnableRewind(); 吗?我使用上面的代码,效果很好。
  • 已经使用 req.EnableRewind();不起作用。我得到 Position = 0,body length = 26,但读取“body”流会得到一个空字符串。
  • 这是完美的答案
  • 也可以使用request.EnableBuffering()(包装在EnableRewind()上)它在ASP.NET Core 2.1中可用docs.microsoft.com/en-us/dotnet/api/…
【解决方案2】:

为了能够回退请求正文,@Jean 的回答帮助我想出了一个似乎运作良好的解决方案。我目前将这个用于全局异常处理中间件,但原理是一样的。

我创建了一个中间件,它基本上启用了请求正文的倒带(而不是装饰器)。

using Microsoft.AspNetCore.Http.Internal;
[...]
public class EnableRequestRewindMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext context)
    {
        context.Request.EnableRewind();
        await _next(context);
    }
}

public static class EnableRequestRewindExtension
{
    public static IApplicationBuilder UseEnableRequestRewind(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<EnableRequestRewindMiddleware>();
    }
}

然后可以在您的Startup.cs 中使用,如下所示:

[...]
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    [...]
    app.UseEnableRequestRewind();
    [...]
}

使用这种方法,我已经能够成功回退请求正文流。

【讨论】:

  • 这对我很有用 @SaoBiz 谢谢! 一个错字,将 @987654324 中的第二个 this 更改为 builder @.
  • @RichardLogwood 很高兴它有帮助!感谢您找到错字!固定的。 :)
  • 这对我很有帮助——而且有效,但在 5.0(或者我认为是 3.1 版本)中,您必须将 context.Request.EnableRewind() 更改为 context.Request.EnableBuffering()。然而,我随后意识到斯蒂芬威尔金森的回答“快速方法......”对我来说更加简洁。
【解决方案3】:

如果你想走这条路,IHttpContextAccessor 方法确实有效。

TLDR;

  • 注入IHttpContextAccessor

  • 倒带 -- HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);

  • 读取 -- System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body); JObject asObj = JObject.Parse(sr.ReadToEnd());

更多 -- 尝试一个简洁的、非编译的示例,您需要确保这些项目已就位,以便获得可用的IHttpContextAccessor。 答案正确地指出,当您尝试阅读请求正文时,您需要回到起点。请求正文流上的 CanSeekPosition 属性有助于验证这一点。

.NET Core DI Docs

// First -- Make the accessor DI available
//
// Add an IHttpContextAccessor to your ConfigureServices method, found by default
// in your Startup.cs file:
// Extraneous junk removed for some brevity:
public void ConfigureServices(IServiceCollection services)
{
    // Typical items found in ConfigureServices:
    services.AddMvc(config => { config.Filters.Add(typeof(ExceptionFilterAttribute)); });
    // ...

    // Add or ensure that an IHttpContextAccessor is available within your Dependency Injection container
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

// Second -- Inject the accessor
//
// Elsewhere in the constructor of a class in which you want
// to access the incoming Http request, typically 
// in a controller class of yours:
public class MyResourceController : Controller
{
    public ILogger<PricesController> Logger { get; }
    public IHttpContextAccessor HttpContextAccessor { get; }

    public CommandController(
        ILogger<CommandController> logger,
        IHttpContextAccessor httpContextAccessor)
    {
        Logger = logger;
        HttpContextAccessor = httpContextAccessor;
    }

    // ...

    // Lastly -- a typical use 
    [Route("command/resource-a/{id}")]
    [HttpPut]
    public ObjectResult PutUpdate([FromRoute] string id, [FromBody] ModelObject requestModel)
    {
        if (HttpContextAccessor.HttpContext.Request.Body.CanSeek)
        {
            HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
            System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body);
            JObject asObj = JObject.Parse(sr.ReadToEnd());

            var keyVal = asObj.ContainsKey("key-a");
        }
    }
}    

【讨论】:

    【解决方案4】:

    更清晰的解决方案,适用于 ASP.Net Core 2.1 / 3.1

    过滤器类

    using Microsoft.AspNetCore.Authorization;
    // For ASP.NET 2.1
    using Microsoft.AspNetCore.Http.Internal;
    // For ASP.NET 3.1
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    public class ReadableBodyStreamAttribute : AuthorizeAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            // For ASP.NET 2.1
            // context.HttpContext.Request.EnableRewind();
            // For ASP.NET 3.1
            // context.HttpContext.Request.EnableBuffering();
        }
    }
    

    在控制器中

    [HttpPost]
    [ReadableBodyStream]
    public string SomePostMethod()
    {
        //Note: if you're late and body has already been read, you may need this next line
        //Note2: if "Note" is true and Body was read using StreamReader too, then it may be necessary to set "leaveOpen: true" for that stream.
        HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
    
        using (StreamReader stream = new StreamReader(HttpContext.Request.Body))
        {
            string body = stream.ReadToEnd();
            // body = "param=somevalue&param2=someothervalue"
        }
    }
    

    【讨论】:

    • 对于 netcore3.0,它将是 .EnableBuffering() 而不是 .EnableRewind()
    • 谢谢@mr5 - 更新了我的答案
    • 我在修复一些破坏 EnableRewind() 方式的 .net Core 2.2 --> Core 3.1 升级时发现了这一点。我认为这需要多行代码,没有它我无法重新阅读正文:HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
    • 这仅在将 AuthorizeAttribute 更改为 Attribute(在 ASP.Net Core 3.1 中)后对我有用。
    • 请确保添加提到的库。我已经有了代码,但 EnableBuffering 显示红色波浪线,直到我意识到缺少 Microsoft.AspNetCore.Http 引用。感谢 Android!
    【解决方案5】:

    我在使用 ASP.NET Core 2.1 时遇到了类似的问题:

    • 我需要一个自定义中间件来读取 POST 数据并对其执行一些安全检查
    • 使用授权过滤器是不切实际的,因为会影响大量操作
    • 我必须允许在动作中绑定对象([FromBody] someObject)。感谢SaoBiz 指出这个解决方案。

    因此,显而易见的解决方案是允许请求可回退,但要确保在读取正文后,绑定仍然有效。

    EnableRequestRewindMiddleware

    public class EnableRequestRewindMiddleware
    {
        private readonly RequestDelegate _next;
    
        ///<inheritdoc/>
        public EnableRequestRewindMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context)
        {
            context.Request.EnableRewind();
            await _next(context);
        }
    }
    

    Startup.cs

    (将其放在 Configure 方法的开头)

    app.UseMiddleware<EnableRequestRewindMiddleware>();
    

    其他一些中间件

    这是中间件的一部分,需要解压 POSTed 信息以检查内容。

    using (var stream = new MemoryStream())
    {
        // make sure that body is read from the beginning
        context.Request.Body.Seek(0, SeekOrigin.Begin);
        context.Request.Body.CopyTo(stream);
        string requestBody = Encoding.UTF8.GetString(stream.ToArray());
    
        // this is required, otherwise model binding will return null
        context.Request.Body.Seek(0, SeekOrigin.Begin);
    }
    

    【讨论】:

      【解决方案6】:

      对于Body的读取,可以异步读取。

      使用async 方法,如下所示:

      public async Task<IActionResult> GetBody()
      {
            string body="";
            using (StreamReader stream = new StreamReader(Request.Body))
            {
                 body = await stream.ReadToEndAsync();
            }
          return Json(body);
      }
      

      用邮递员测试:

      Asp.net core 版本2.0 , 2.1 , 2.2, 3.0 中运行良好并经过测试。

      希望有用。

      【讨论】:

      • 赞成,因为这似乎是最干净且唯一的版本弹性答案;)
      【解决方案7】:

      我还想阅读 Request.Body 而不自动将其映射到某个动作参数模型。在解决这个问题之前测试了很多不同的方法。而且我没有找到这里描述的任何可行的解决方案。该解决方案目前基于 .NET Core 3.0 框架。

      reader.readToEnd() 像一个简单的方法一样接缝,即使它已编译,它也会引发运行时异常,需要我使用异步调用。所以我改为使用 ReadToEndAsync(),但它有时有效,有时无效。给我错误之类的错误,流关闭后无法读取。问题是我们不能保证它会在同一个线程中返回结果(即使我们使用了 await)。所以我们需要某种回调。这个解决方案对我有用。

      [Route("[controller]/[action]")]
      public class MyController : ControllerBase
      {
      
          // ...
      
          [HttpPost]
          public async void TheAction()
          {
              try
              {
                  HttpContext.Request.EnableBuffering();
                  Request.Body.Position = 0;
                  using (StreamReader stream = new StreamReader(HttpContext.Request.Body))
                  {
                      var task = stream
                          .ReadToEndAsync()
                          .ContinueWith(t => {
                              var res = t.Result;
                              // TODO: Handle the post result!
                          });
      
                      // await processing of the result
                      task.Wait();
                  }
              }
              catch (Exception ex)
              {
                  _logger.LogError(ex, "Failed to handle post!");
              }
          }
      

      【讨论】:

        【解决方案8】:

        这是一个有点老的帖子,但自从我来到这里,我想我会发布我的发现,以便他们可以帮助其他人。

        首先,我遇到了同样的问题,我想获取 Request.Body 并对其进行处理(日志记录/审计)。但除此之外,我希望端点看起来相同。

        所以,EnableBuffering() 调用似乎可以解决问题。然后你可以在 body 上做一个 Seek(0,xxx) 并重新读取内容等。

        然而,这导致了我的下一个问题。访问端点时,我会收到“不允许同步操作”异常。因此,解决方法是在选项中设置属性 AllowSynchronousIO = true。有很多方法可以做到这一点(但这里不重要..)

        那么,下一个问题是,当我阅读 Request.Body 时,它已经被处理掉了。啊。那么,什么给了?

        我在 endpiont 调用中使用 Newtonsoft.JSON 作为我的 [FromBody] 解析器。这就是同步读取的原因,它在完成时也会关闭流。解决方案?在进行 JSON 解析之前读取流?当然,这行得通,我最终得到了这个:

         /// <summary>
        /// quick and dirty middleware that enables buffering the request body
        /// </summary>
        /// <remarks>
        /// this allows us to re-read the request body's inputstream so that we can capture the original request as is
        /// </remarks>
        public class ReadRequestBodyIntoItemsAttribute : AuthorizeAttribute, IAuthorizationFilter
        {
            public void OnAuthorization(AuthorizationFilterContext context)
            {
                if (context == null) return;
        
                // NEW! enable sync IO beacuse the JSON reader apparently doesn't use async and it throws an exception otherwise
                var syncIOFeature = context.HttpContext.Features.Get<IHttpBodyControlFeature>();
                if (syncIOFeature != null)
                {
                    syncIOFeature.AllowSynchronousIO = true;
        
                    var req = context.HttpContext.Request;
        
                    req.EnableBuffering();
        
                    // read the body here as a workarond for the JSON parser disposing the stream
                    if (req.Body.CanSeek)
                    {
                        req.Body.Seek(0, SeekOrigin.Begin);
        
                        // if body (stream) can seek, we can read the body to a string for logging purposes
                        using (var reader = new StreamReader(
                             req.Body,
                             encoding: Encoding.UTF8,
                             detectEncodingFromByteOrderMarks: false,
                             bufferSize: 8192,
                             leaveOpen: true))
                        {
                            var jsonString = reader.ReadToEnd();
        
                            // store into the HTTP context Items["request_body"]
                            context.HttpContext.Items.Add("request_body", jsonString);
                        }
        
                        // go back to beginning so json reader get's the whole thing
                        req.Body.Seek(0, SeekOrigin.Begin);
                    }
                }
            }
        }
        

        所以现在,我可以在具有 [ReadRequestBodyIntoItems] 属性的端点中使用 HttpContext.Items["request_body"] 访问正文。

        但是,伙计,这似乎是太多的箍要跳过。所以这就是我结束的地方,我真的很高兴。

        我的端点开始类似于:

        [HttpPost("")]
        [ReadRequestBodyIntoItems]
        [Consumes("application/json")]
        public async Task<IActionResult> ReceiveSomeData([FromBody] MyJsonObjectType value)
        {
            val bodyString = HttpContext.Items["request_body"];
            // use the body, process the stuff...
        }
        

        但是更改签名要简单得多,如下所示:

        [HttpPost("")]
        [Consumes("application/json")]
        public async Task<IActionResult> ReceiveSomeData()
        {
            using (var reader = new StreamReader(
                   Request.Body,
                   encoding: Encoding.UTF8,
                   detectEncodingFromByteOrderMarks: false
            ))
            {
                var bodyString = await reader.ReadToEndAsync();
        
                var value = JsonConvert.DeserializeObject<MyJsonObjectType>(bodyString);
        
                // use the body, process the stuff...
            }
        }
        

        我真的很喜欢这个,因为它只读取一次正文流,并且我可以控制反序列化。当然,如果 ASP.NET core 能为我做到这一点,那就太好了,但是在这里我不会浪费时间读取两次流(可能每次都缓冲),并且代码非常清晰。

        如果您在很多端点上都需要此功能,也许中间件方法可能更简洁,或者您至少可以将主体提取封装到扩展函数中以使代码更简洁。

        无论如何,我没有找到任何涉及这个问题的所有 3 个方面的来源,因此这篇文章。希望这可以帮助某人!

        顺便说一句:这是使用 ASP .NET Core 3.1。

        【讨论】:

        • 如果程序无法将 JSON 字符串解析为 NyObjectType,则无法从“request_body”中读取值
        【解决方案9】:

        我能够在这样的 asp.net core 3.1 应用程序中读取请求正文(连同一个启用缓冲的简单中间件-启用倒带似乎适用于早期的 .Net Core 版本-):

        var reader = await Request.BodyReader.ReadAsync();
        Request.Body.Position = 0;
        var buffer = reader.Buffer;
        var body = Encoding.UTF8.GetString(buffer.FirstSpan);
        Request.Body.Position = 0;
        

        【讨论】:

          【解决方案10】:

          最简单的方法如下:

          1. 在需要从中提取主体的 Controller 方法中,添加以下参数: [FromBody] SomeClass 值

          2. 将“SomeClass”声明为: 类SomeClass { 公共字符串 SomeParameter { 获取;放; } }

          当原始正文以 json 格式发送时,.net 核心知道如何轻松读取它。

          【讨论】:

            【解决方案11】:

            最近我遇到了一个非常优雅的解决方案,它接收你不知道结构的随机 JSON:

                [HttpPost]
                public JsonResult Test([FromBody] JsonElement json)
                {
                    return Json(json);
                }
            

            就这么简单。

            【讨论】:

            • 谢谢,它确实有效。我使用了 JsonElement 的 GetRawText() 方法并收到了我的 JSON 文本。
            • 如果 DTO 在您创建它时进行一些处理,例如设置默认值或其他内容,这不会为您提供实际的请求正文。
            • @EbramShehata - 你能澄清一下你的意思吗?据我所知,@naspinski 建议的方法会将 JSON 正文读入JsonElement。如果在将其转换为 DTO 时发生任何处理,那么这将发生在该点之后
            • 这会保留空白吗?使用哈希验证请求意味着我们需要确切的内容。可惜 asp.net 核心让这变得如此困难
            【解决方案12】:

            对于那些只想从请求中获取内容(请求正文)的人:

            在控制器方法参数中使用[FromBody] 属性。

            [Route("api/mytest")]
            [ApiController]
            public class MyTestController : Controller
            {
                [HttpPost]
                [Route("content")]
                public async Task<string> ReceiveContent([FromBody] string content)
                {
                    // Do work with content
                }
            }
            

            正如文档所说:此属性指定应使用请求正文绑定参数或属性。

            【讨论】:

            • 这行不通。这将尝试将 json 主体 反序列化string 对象。但是 body json 不适合字符串对象的形状。
            【解决方案13】:

            在 .NET Core 3.1 中添加响应缓冲的快速方法是

                app.Use((context, next) =>
                {
                    context.Request.EnableBuffering();
                    return next();
                });
            

            在 Startup.cs 中。我发现这还可以保证在读取流之前启用缓冲,这对于 .Net Core 3.1 和我见过的其他一些中间件/授权过滤器答案来说是个问题。

            然后您可以按照其他人的建议通过处理程序中的HttpContext.Request.Body 阅读您的请求正文。

            另外值得考虑的是EnableBuffering 具有重载,允许您限制它在使用临时文件之前将在内存中缓冲多少,以及对您的缓冲区的总体限制。请注意,如果请求超过此限制,则会引发异常,并且请求将永远不会到达您的处理程序。

            【讨论】:

            • 这对我来说非常有效(3.1)。在另一个问题上引用了你的话:stackoverflow.com/a/63525694/6210068
            • 在 3.1 上工作。另外,只是提醒将要使用它的用户:确保在 Startup.cs 中以正确的顺序放置它。
            • @EbramShehata - 正确的顺序是什么?
            • 在@EbramShehata 没有回复的情况下,我发现这将特别需要在任何调用 app.UseEndpoints 之前放置。
            • 请注意,在您的 startup.cs 中,您应该在设置 UseEndpoints 之前放置 EnableBuffering 代码。
            【解决方案14】:

            这是POSTed JSON body 的解决方案,不需要任何中间件或扩展,您只需覆盖 OnActionExecuting 即可访问正文中的所有数据集甚至参数在网址中:

            using System.Text.Json;
            
            ....
            
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                base.OnActionExecuting(filterContext);
                
                // You can simply use filterContext.ActionArguments to get whatever param that you have set in the action
                // For instance you can get the "json" param like this: filterContext.ActionArguments["json"]
                // Or better yet just loop through the arguments and find the type
                foreach(var elem in filterContext.ActionArguments)
                {
                    if(elem.Value is JsonElement)
                    {
                        // Convert json obj to string
                        var json = ((JsonElement)elem.Value).GetRawText();
                        break;
                    }
                }
            }
            
            [HttpPost]
            public IActionResult Add([FromBody] JsonElement json, string id = 1)
            {
                return Ok("v1");
            }
            

            【讨论】:

              【解决方案15】:

              在我看来,写一个扩展方法是最有效的方法

               public static string PeekBody(this HttpRequest request)
                      {
                          try
                          {
                              request.EnableBuffering();
                              var buffer = new byte[Convert.ToInt32(request.ContentLength)];
                              request.Body.Read(buffer, 0, buffer.Length);
                              return Encoding.UTF8.GetString(buffer);
                          }
                          finally
                          {
                              request.Body.Position = 0;
                          }
                      }
              

              您也可以使用Request.Body.Peeker Nuget 包 (source code)

              //Return string
              var request = HttpContext.Request.PeekBody();
              
              //Return in expected type
              LoginRequest request = HttpContext.Request.PeekBody<LoginRequest>();
              
              //Return in expected type asynchronously
              LoginRequest request = await HttpContext.Request.PeekBodyAsync<LoginRequest>();
              

              【讨论】:

                【解决方案16】:

                我知道我迟到了,但就我而言,只是我在路由时遇到了问题,如下所示 在 startup.cs 文件中,我使用 /api 开始路由

                app.MapWhen(context => context.Request.Path.StartsWithSegments(new PathString("/api")),
                            a =>
                            {
                                //if (environment.IsDevelopment())
                                //{
                                //  a.UseDeveloperExceptionPage();
                                //}
                
                                a.Use(async (context, next) =>
                                {
                                    // API Call
                                    context.Request.EnableBuffering();
                                    await next();
                                });
                        //and I was putting in controller 
                    [HttpPost]
                    [Route("/Register", Name = "Register")]
                        //Just Changed the rout to start with /api like my startup.cs file
                    [HttpPost]
                    [Route("/api/Register", Name = "Register")]
                    /and now the params are not null and I can ready the body request multiple
                

                【讨论】:

                  【解决方案17】:

                  我在 .NET5.0 下遇到了同样的问题,上面的解决方案都没有奏效。 原来问题出在 Post 方法的返回值上。 必须是Task,不能为空。

                  错误代码:

                  [HttpPost]
                  public async void Post() {...}
                  

                  好代码:

                  [HttpPost]
                  public async Task Post() {...}
                  

                  【讨论】:

                    猜你喜欢
                    • 2020-03-23
                    • 2021-08-12
                    • 1970-01-01
                    • 2018-04-27
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-12-23
                    • 1970-01-01
                    相关资源
                    最近更新 更多