gpt4 book ai didi

c# - ASP.NET MVC Core 3.0 - 为什么来自主体的 API 请求不断返回!ModelState.IsValid?

转载 作者:行者123 更新时间:2023-12-05 09:12:13 24 4
gpt4 key购买 nike

我目前正在使用 ASP.NET MVC Core 3.0 创建一个 API 项目。我成功发送了一个不带参数的POST请求。但目前我在尝试通过 Postman 发送带有 JSON 参数的 POST 请求时遇到问题,总是收到无效请求,如下所示。

enter image description here

请注意,查询字符串中还有 key 参数,用于使用我创建的中间件授权请求。这部分没有问题。

Controller 代码如下:

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
// POST api/values
[HttpPost]
public IActionResult Post([FromBody] UserRequest model)
{
if (!ModelState.IsValid)
return BadRequest(new ApiResponse(400, "Model state is not valid."));

return Ok($"Hello world, {model.Id}!");
}
}

奇怪的是,我已经创建了 UserRequest 类并将其用作参数输入,如下所示:

public class UserRequest
{
public string Id { get; set; }
}

这是我的 Startup.cs 设置,我已经添加了 AddNewtonsoftJson 以启用 JSON 序列化器输入:

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(option => option.EnableEndpointRouting = false)
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddNewtonsoftJson(opt => opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);

/*Other API, DB settings and services goes here*/
...
}

到目前为止,这是我的尝试:

  1. UserRequest 类上添加了 [BindProperties]。仍然返回相同的错误。
  2. 删除了 Controller 参数上的[FromBody]。仍然返回相同的错误。
  3. id 重命名为 Id 以遵循 UserRequest 类中的命名。仍然返回相同的错误。
  4. Startup.cs 上添加了这段代码,这将执行 return BadRequest(new ApiResponse(400, "Model state is not valid.")); :

    .ConfigureApiBehaviorOptions(options =>
    {
    options.SuppressModelStateInvalidFilter = true;
    })
  5. Startup.cs 上删除了这段代码

    .AddNewtonsoftJson(opt => opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore)

    它会返回这个:

    {
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "|f6037d12-44fa46ceaffd3dba.",
    "errors": {
    "$": [
    "The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0."
    ]
    }
    }

如有任何帮助,我们将不胜感激。

12/11/2019 更新:以下是我处理 API key 请求的方式:

public async Task Invoke(HttpContext httpContext, IApiKeyService apiKeyService)
{
var remoteIpAddress = httpContext.Connection.RemoteIpAddress;

if (httpContext.Request.Path.StartsWithSegments("/api"))
{
_logger.LogInformation($"Request from {remoteIpAddress}.");

var queryString = httpContext.Request.Query;
queryString.TryGetValue("key", out var keyValue);

if (keyValue.ToString().Any(char.IsWhiteSpace))
keyValue = keyValue.ToString().Replace(" ", "+");

if (httpContext.Request.Method != "POST")
{
httpContext.Response.StatusCode = StatusCodes.Status405MethodNotAllowed;
await WriteJsonResponseAsync(httpContext, "Only POST method is allowed.");
return;
}

if (keyValue.Count == 0)
{
httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
await WriteJsonResponseAsync(httpContext, "API Key is missing.");
return;
}

var isKeyValid = await apiKeyService.IsApiKeyValidAsync(keyValue);
var isKeyActive = await apiKeyService.IsApiKeyActiveAsync(keyValue);

if (!isKeyValid)
{
httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
await WriteJsonResponseAsync(httpContext, "Invalid API Key.");
return;
}

if (!isKeyActive)
{
httpContext.Response.StatusCode = StatusCodes.Status406NotAcceptable;
await WriteJsonResponseAsync(httpContext, "Service is Deactivated.");
return;
}
}
await _next.Invoke(httpContext);
}

private static async Task WriteJsonResponseAsync(HttpContext httpContext, string message = null)
{
httpContext.Response.ContentType = "application/json";
var response = new ApiResponse(httpContext.Response.StatusCode, message);
var json = JsonConvert.SerializeObject(response);
await httpContext.Response.WriteAsync(json);
}

最佳答案

正如评论中所讨论的,您的日志记录中间件导致了问题。当您读取请求主体或响应主体时,您需要重置流以便其他中间件可以读取它(在本例中为 JsonSerializer)。

在您的日志记录中间件中,您将进行如下调用:

var body = await new StreamReader(request.Body).ReadToEndAsync();

在该方法返回之前,您需要重置该流:

request.Body.Seek(0, SeekOrigin.Begin);

这对于响应代码是相同的,例如

response.Body.Seek(0, SeekOrigin.Begin);

编辑

按照评论中的要求,这里是中间件代码的示例:

public class LoggingMiddleware
{
private readonly RequestDelegate _next;

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

public async Task Invoke(HttpContext context)
{
context.Request.EnableBuffering();
var body = await new StreamReader(context.Request.Body).ReadToEndAsync();

// Log the contents of body...

context.Request.Body.Seek(0, SeekOrigin.Begin);

await _next(context);
}
}

重置 Body 流位置的代码需要在调用 _next(context) 之前出现

关于c# - ASP.NET MVC Core 3.0 - 为什么来自主体的 API 请求不断返回!ModelState.IsValid?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58812020/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com