Rey*_*ldi 2 c# asp.net-web-api asp.net-core
我目前正在使用ASP.NET MVC Core 3.0创建一个 API 项目。我成功发送了一个没有参数的 POST 请求。但是目前我在尝试通过 Postman 发送带有 JSON 参数的 POST 请求时遇到问题,总是收到无效请求,如下所示。
请注意,key查询字符串中还有param 用于使用我创建的中间件授权请求。这部分没有问题。
这是控制器的代码:
[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}!");
}
}
Run Code Online (Sandbox Code Playgroud)
奇怪的是,我已经创建并使用了类 UserRequest 作为参数输入,如下所示:
public class UserRequest
{
public string Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这是我的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*/
...
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,这是我的尝试:
[BindProperties]到UserRequest课堂上。仍然返回相同的错误。[FromBody]在控制器参数上删除。仍然返回相同的错误。id为Id遵循UserRequest类内部的命名。仍然返回相同的错误。在 上添加了此代码Startup.cs,这将执行return BadRequest(new ApiResponse(400, "Model state is not valid."));:
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = true;
})
Run Code Online (Sandbox Code Playgroud)删除了此代码 Startup.cs
.AddNewtonsoftJson(opt => opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore)
Run Code Online (Sandbox Code Playgroud)
它会返回这个:
{
"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."
]
}
}
Run Code Online (Sandbox Code Playgroud)任何帮助将不胜感激。
2019 年 12 月 11 日更新:以下是我处理 API 密钥请求的方式:
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);
}
Run Code Online (Sandbox Code Playgroud)
正如评论中所讨论的,您的日志记录中间件导致了问题。当您读取请求正文或响应正文时,您需要重置流以便其他中间件可以读取它(在本例中为 JsonSerializer)。
在您的日志中间件中,您将有一个类似的调用:
var body = await new StreamReader(request.Body).ReadToEndAsync();
Run Code Online (Sandbox Code Playgroud)
在该方法返回之前,您需要重置该流:
request.Body.Seek(0, SeekOrigin.Begin);
Run Code Online (Sandbox Code Playgroud)
这与响应代码相同,例如
response.Body.Seek(0, SeekOrigin.Begin);
Run Code Online (Sandbox Code Playgroud)
编辑
根据评论中的要求,这里是中间件代码可能是什么的示例:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
重置Body流位置的代码需要在调用之前出现_next(context)
| 归档时间: |
|
| 查看次数: |
5922 次 |
| 最近记录: |