我正在寻找在我的.NET Core Web API控制器中用HTTP状态代码返回JSON的正确方法。我以前是这样使用的。
public IHttpActionResult GetResourceData()
{
return this.Content(HttpStatusCode.OK, new { response = "Hello"});
}
这是在4.6 MVC应用程序中,但现在在.NET Core中,我似乎没有这个IHttpActionResult
,我有ActionResult
,并像这样使用。
public ActionResult IsAuthenticated()
{
return Ok(Json("123"));
}
但服务器的响应却很奇怪,如下图所示。
我只是想让Web API控制器像在Web API 2中那样返回带有HTTP状态码的JSON。
用JsonResult
响应的最基本版本是。
// GET: api/authors
[HttpGet]
public JsonResult Get()
{
return Json(_authorRepository.List());
}
然而,这对你的问题没有帮助,因为你不能明确地处理自己的响应代码。
要想控制状态结果,你需要返回一个 "ActionResult",在这里你可以利用 "StatusCodeResult "类型。
例如。
// GET: api/authors/search?namelike=foo
[HttpGet("Search")]
public IActionResult Search(string namelike)
{
var result = _authorRepository.GetByNameSubstring(namelike);
if (!result.Any())
{
return NotFound(namelike);
}
return Ok(result);
}
注意以上两个例子都来自微软文档中的一个很好的指南。格式化响应数据
我经常遇到的问题是,我想对我的WebAPI进行更精细的控制,而不是仅仅使用VS中"新项目"模板的默认配置。
让我们确保你有一些基本的东西......
为了让你的ASP.NET Core WebAPI用JSON序列化对象来响应,并完全控制状态代码,你应该首先确保你已经在Startup.cs
中的ConfigureServices
方法中包含了AddMvc()
服务。
值得注意的是,AddMvc()
将自动包含JSON的输入/输出格式化器,以及对其他请求类型的响应。
如果你的项目需要完全控制,并且你想严格定义你的服务,例如你的WebAPI将如何对包括application/json
在内的各种请求类型作出反应,而不对其他请求类型(例如标准的浏览器请求)作出反应,你可以用以下代码手动定义。
public void ConfigureServices(IServiceCollection services)
{
// Build a customized MVC implementation, without using the default AddMvc(), instead use AddMvcCore().
// https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc/MvcServiceCollectionExtensions.cs
services
.AddMvcCore(options =>
{
options.RequireHttpsPermanent = true; // does not affect api requests
options.RespectBrowserAcceptHeader = true; // false by default
//options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
//remove these two below, but added so you know where to place them...
options.OutputFormatters.Add(new YourCustomOutputFormatter());
options.InputFormatters.Add(new YourCustomInputFormatter());
})
//.AddApiExplorer()
//.AddAuthorization()
.AddFormatterMappings()
//.AddCacheTagHelper()
//.AddDataAnnotations()
//.AddCors()
.AddJsonFormatters(); // JSON, or you can build your own custom one (above)
}
你会注意到,我还为你提供了一种方法来添加你自己的自定义输入/输出格式器,以备你可能想要响应另一种序列化格式(protobuf、thrift等)。
上面这段代码大部分是对AddMvc()
方法的重复。然而,我们是通过定义每一个服务来实现每一个"default"服务,而不是用模板的预装服务。我在代码块中添加了仓库链接,或者你可以从GitHub仓库中查看AddMvc()
2。
*请注意,有些指南会试图通过"撤销"默认值来解决这个问题,而不是一开始就不实现它......如果你考虑到我们现在正在与开源合作,这就是多余的工作,糟糕的代码,坦率地说是一个很快就会消失的旧习惯。
我将向你展示一个非常简单的,只是为了让你的问题得到解决。
public class FooController
{
[HttpPost]
public async Task<IActionResult> Create([FromBody] Object item)
{
if (item == null) return BadRequest();
var newItem = new Object(); // create the object to return
if (newItem != null) return Ok(newItem);
else return NotFound();
}
}
Content-Type
和Accept
你需要确保你的**请求中的 "Content-Type "和 "Accept "头文件设置正确。在你的情况下(JSON),你要把它设置为application/json
。
如果你想让你的WebAPI默认以JSON方式响应,不管请求头是什么,你可以用**种方式来做。
方法1 正如我之前推荐的文章(格式化响应数据)中所示,你可以在控制器/行动层面强制采用特定的格式。我个人不喜欢这种方法......但为了完整起见,我在这里介绍一下。
强制特定格式 如果你想限制特定动作的响应格式,你可以,你可以应用 [Produces]过滤器。[Produces]过滤器指定了特定动作的响应 特定动作(或控制器)的响应格式。像大多数过滤器一样,这个 可以在动作、控制器或全局范围内应用。
[Produces("application/json") public class AuthorsController
[Produces]
过滤器将强制所有在AuthorsController
将返回JSON格式的响应,即使其他的 为应用程序配置了格式化器,并且客户端提供了 `Accept'标头要求使用不同的可用格式。
方式2 我的首选方法是让WebAPI用请求的格式来响应所有请求。然而,如果它不接受所请求的格式,则**回落到默认格式(即JSON)。
首先,你需要在你的选项中注册(我们需要重新设计默认行为,如前所述)。
options.RespectBrowserAcceptHeader = true; // false by default
最后,通过简单地重新排列在服务构建器中定义的格式器列表,虚拟主机将默认为你定位在列表顶部的格式器(即位置0)。
更多信息可以在这个.NET网站开发和工具博客条目中找到。
你有预定义的方法来处理大多数常见的状态代码。
Ok(result)
返回200
和响应。CreatedAtRoute
返回201
+新的资源URL。NotFound
返回404
。BadRequest
返回400
等等。所有方法的列表见 BaseController.cs
和 Controller.cs
。
但如果你真的坚持,你可以使用StatusCode
来设置一个自定义的代码,但你真的不应该这样做,因为它使代码的可读性降低,你将不得不重复代码来设置标题(比如对于CreatedAtRoute
)。
public ActionResult IsAuthenticated()
{
return StatusCode(200, "123");
}
请参考以下代码,你可以用不同类型的JSON管理多个状态代码
public async Task<HttpResponseMessage> GetAsync()
{
try
{
using (var entities = new DbEntities())
{
var resourceModelList = entities.Resources.Select(r=> new ResourceModel{Build Your Resource Model}).ToList();
if (resourceModelList.Count == 0)
{
return this.Request.CreateResponse<string>(HttpStatusCode.NotFound, "No resources found.");
}
return this.Request.CreateResponse<List<ResourceModel>>(HttpStatusCode.OK, resourceModelList, "application/json");
}
}
catch (Exception ex)
{
return this.Request.CreateResponse<string>(HttpStatusCode.InternalServerError, "Something went wrong.");
}
}