[英]ASP.NET 5 Web API CreatedAtAction: POST returns 500
I have a simple ASP.NET 5 Web API with a controller for uploading/downloading files, like:我有一个简单的 ASP.NET 5 Web API,带有一个用于上传/下载文件的控制器,例如:
[Authorize(Roles = "admin,browser,writer")]
[HttpPost("api/contents/{id}")]
public IActionResult UploadContent(IFormFile file,
[FromForm] string mimeType,
[FromForm] string id)
{
// store...
return CreatedAtAction(nameof(DownloadContent), new
{
id = id
});
}
[Authorize]
[HttpGet("api/contents/{id}")]
public FileResult DownloadContent([FromRoute] string id)
{
// fetch into item...
return File(item.Content, item.MimeType);
}
The upload action works fine, until the method returns: at this point, when the framework handles the serialization for the 201 return object (which should set its location to the corresponding download action) I get an InvalidOperationException
telling that No route matches the supplied values
.上传操作正常工作,直到该方法返回:此时,当框架处理 201 返回对象的序列化(应将其位置设置为相应的下载操作)时,我得到一个
InvalidOperationException
告诉我No route matches the supplied values
.
I found this issue about a similar problem, but none of the mentioned solutions seem to work.我发现 这个问题是关于一个类似的问题,但提到的解决方案似乎都不起作用。 I tried:
我试过了:
[ActionName("DownloadContent")]
, even though this should not make any difference;[ActionName("DownloadContent")]
显式命名下载操作,即使这应该没有任何区别; this appears to be relevant only when the action name ends with Async
(see this post , and the official issue ).Async
结尾时才相关(请参阅此帖子和官方问题)。CreatedAtRoute
instead, by adding the corresponding Name="DownloadContent"
in the HttpGet attribute of DownloadContent
.CreatedAtRoute
代替,通过加入相应的Name="DownloadContent"
中的属性HTTPGET DownloadContent
。CreatedAtActionResult
like:CreatedAtActionResult
像:return new CreatedAtActionResult(nameof(DownloadContent),
nameof(ItemContentController), new { id = id }, null);
CreatedResult
object:CreatedResult
对象:string url = Url.Action(new UrlActionContext
{
Protocol = Request.Scheme,
Host = Request.Host.Value,
Action = nameof(DownloadContent)
});
return new CreatedResult(url, null);
Now, that's the point: the above code returns null
for the url
, and this then makes CreatedResult
throw as the url
for the 201 header's Location
is null.现在,这就是重点:上面的代码为
url
返回null
,然后这使CreatedResult
抛出,因为 201 标头的Location
的url
为 null。 If I change this code by selecting a different action, eg Action = nameof(UploadContent)
, it works, and I get the URL for the action.如果我通过选择不同的操作来更改此代码,例如
Action = nameof(UploadContent)
,它会起作用,并且我会获得该操作的 URL。
For completeness, my Startup.cs
Configure
method is like this:为了完整
Startup.cs
,我的Startup.cs
Configure
方法是这样的:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor
| ForwardedHeaders.XForwardedProto
});
if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
else
{
app.UseExceptionHandler("/Error");
if (Configuration.GetValue<bool>("Server:UseHSTS")) app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
// ... Swagger stuff ...
}
When using overload CreatedAtAction(string, object)
, param object
is not route parameters as you assume, but body content.使用重载
CreatedAtAction(string, object)
,param object
不是您假设的路由参数,而是正文内容。 Hence, code is looking for a route to GET api/contents which doesn't exists.因此,代码正在寻找一条不存在的 GET api/contents路线。
You'll need to use overload CreatedAtAction(string, object, object)
where param #2 contains route params, and param #3 contains body content.您需要使用重载
CreatedAtAction(string, object, object)
其中 param #2 包含路由参数,而 param #3 包含正文内容。 So in your case, return CreatedAtAction(nameof(DownloadContent), new { id = id }, null);
所以在你的情况下,
return CreatedAtAction(nameof(DownloadContent), new { id = id }, null);
will work.将工作。
I was able to reproduce your issue with this controller and Postman:我能够使用此控制器和邮递员重现您的问题:
public class MyContentController : ControllerBase
{
[HttpGet("api/contents/{id}")]
public IActionResult DownloadContent(int id)
{
return Ok(1);
}
[HttpPost("api/contents/{id}")]
public IActionResult UploadContent(int id)
{
return CreatedAtAction(nameof(DownloadContent), new { id = id });
}
}
I got expected response when replacing更换时我得到了预期的响应
return CreatedAtAction(nameof(DownloadContent), new { id = id });
with和
return CreatedAtAction(nameof(DownloadContent), new { id = id }, null);
Doc: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.createdataction?view=aspnetcore-5.0#Microsoft_AspNetCore_Mvc_ControllerBase_CreatedAtAction_System_String_System_Object _文档: https : //docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.createdataction? view = aspnetcore-5.0# Microsoft_AspNetCore_Mvc_ControllerBase_CreatedAtAction_System_String_System_Object _
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.