ASP.NET Core返回带有状态代码的JSON

Ros*_*sco 119 c# json asp.net-core asp.net-core-webapi

我正在寻找在我的.NET Core Web API控制器中使用HTTP状态代码返回JSON的正确方法.我用它像这样:

public IHttpActionResult GetResourceData()
{
    return this.Content(HttpStatusCode.OK, new { response = "Hello"});
}
Run Code Online (Sandbox Code Playgroud)

这是一个4.6 MVC应用程序,但现在随着.NET核心我似乎没有这个IHttpActionResult我已经ActionResult和使用这样的:

public ActionResult IsAuthenticated()
{
    return Ok(Json("123"));
}
Run Code Online (Sandbox Code Playgroud)

但是来自服务器的响应很奇怪,如下图所示:

在此输入图像描述

我只是希望Web API控制器返回带有HTTP状态代码的JSON,就像我在Web API 2中所做的那样.

Sve*_*vek 162

用a响应的最基本版本JsonResult是:

// GET: api/authors
[HttpGet]
public JsonResult Get()
{
    return Json(_authorRepository.List());
}
Run Code Online (Sandbox Code Playgroud)

但是,这不会对您的问题有所帮助,因为您无法明确处理自己的响应代码.

控制状态结果的方法是,您需要返回一个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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,上述两个示例均来自Microsoft文档提供的精彩指南:格式化响应数据


额外的东西

我经常遇到的问题是我希望对我的WebAPI进行更精细的控制,而不是仅使用VS中"新建项目"模板的默认配置.

让我们确保你有一些基础知识......

第1步:配置您的服务

为了使您的ASP.NET Core WebAPI能够在完全控制状态代码的情况下使用JSON序列化对象进行响应,您应该首先确保已将该AddMvc()服务包含在ConfigureServices通常找到的方法中Startup.cs.

重要的是要注意,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)
}
Run Code Online (Sandbox Code Playgroud)

您会注意到我还提供了一种方法,您可以添加自己的自定义输入/输出格式化程序,如果您可能想要响应另一种序列化格式(protobuf,thrift等).

上面的代码块大多是AddMvc()方法的副本.但是,我们通过定义每个服务而不是使用预先附带的模板来实现每个"默认"服务.我在代码块中添加了存储库链接,或者您可以AddMvc() 从GitHub存储库中检出..

请注意,有一些指南会试图通过"撤消"默认值来解决这个问题,而不是仅仅是首先实现它...如果你考虑到我们现在正在使用开源,这是多余的工作,糟糕的代码和坦率的旧习惯很快就会消失.


第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();
    }
}
Run Code Online (Sandbox Code Playgroud)

第3步:检查你的Content-TypeAccept

您需要确保正确设置请求中的标头Content-TypeAccept标头.在您的情况下(JSON),您将需要将其设置为.application/json

如果您希望WebAPI作为默认值响应JSON,则无论请求标头指定了什么,您都可以通过几种方式执行此操作.

方式1 如我之前建议的文章(格式化响应数据)所示,您可以在Controller/Action级别强制使用特定格式.我个人不喜欢这种方法......但这里是为了完整性:

强制特定格式如果要限制特定操作的响应格式,可以应用[Produces]过滤器.[Produces]过滤器指定特定操作(或控制器)的响应格式.与大多数过滤器一样,这可以应用于操作,控制器或全局范围.

[Produces("application/json")]
public class AuthorsController
Run Code Online (Sandbox Code Playgroud)

[Produces]过滤器将迫使内的所有动作 AuthorsController返回JSON格式的响应,即使其他格式化被配置为应用程序和客户端提供了一个Accept头,要求不同,可用的格式.

方式2 我首选的方法是让WebAPI以所请求的格式响应所有请求.但是,如果它不接受请求的格式,则回退到默认值(即JSON)

首先,您需要在您的选项中注册(我们需要重做默认行为,如前所述)

options.RespectBrowserAcceptHeader = true; // false by default
Run Code Online (Sandbox Code Playgroud)

最后,通过简单地重新排序服务构建器中定义的格式化程序列表,Web主机将默认为您位于列表顶部的格式化程序(即位置0).

可以在此.NET Web开发和工具博客条目中找到更多信息

  • 为了扩展这个主题,我在这里创建了一个额外的、更完整的 WebAPI 实施指南:http://stackoverflow.com/q/42365275/3645638 (2认同)

Tse*_*eng 49

您有最常见状态代码的预定义方法.

  • Ok(result)返回200响应
  • CreatedAtRoute返回201+新资源URL
  • NotFound 回报 404
  • BadRequest回报400

查看BaseController.csController.cs获取所有方法的列表.

但是,如果你真的坚持你可以StatusCode用来设置自定义代码,但你真的不应该因为它使代码的可读性降低而且你必须重复代码来设置标题(比如for CreatedAtRoute).

public ActionResult IsAuthenticated()
{
    return StatusCode(200, "123");
}
Run Code Online (Sandbox Code Playgroud)


Arg*_*a C 35

使用ASP.NET Core 2.0,返回对象Web API(与MVC统一并使用相同的基类Controller)的理想方法是

public IActionResult Get()
{
    return new OkObjectResult(new Item { Id = 123, Name = "Hero" });
}
Run Code Online (Sandbox Code Playgroud)

请注意

  1. 它返回200 OK状态代码(它是一种Ok类型ObjectResult)
  2. 它进行内容协商,即它将根据Accept请求中的标头返回.如果Accept: application/xml在请求中发送,它将返回为XML.如果未发送任何内容,JSON则为默认值.

如果需要使用特定的状态代码发送,请使用ObjectResultStatusCode代替.两者都做同样的事情,并支持内容协商.

return new ObjectResult(new Item { Id = 123, Name = "Hero" }) { StatusCode = 200 };
return StatusCode( 200, new Item { Id = 123, Name = "Hero" });
Run Code Online (Sandbox Code Playgroud)

如果您特别希望以JSON身份返回,则有几种方法

//GET http://example.com/api/test/asjson
[HttpGet("AsJson")]
public JsonResult GetAsJson()
{
    return Json(new Item { Id = 123, Name = "Hero" });
}

//GET http://example.com/api/test/withproduces
[HttpGet("WithProduces")]
[Produces("application/json")]
public Item GetWithProduces()
{
    return new Item { Id = 123, Name = "Hero" };
}
Run Code Online (Sandbox Code Playgroud)

请注意

  1. 两者都JSON以两种不同的方式强制执行.
  2. 两者都忽略了内容协商.
  3. 第一种方法使用特定的序列化程序强制执行JSON Json(object).
  4. 第二种方法通过使用Produces()属性(即a ResultFilter)来做同样的事情contentType = application/json

官方文档中阅读有关它们的更多信息.在此处了解过滤器.

样本中使用的简单模型类

public class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案,因为它侧重于问题,并简要解释了一些实用性. (9认同)

Ger*_*hes 23

我想出的最简单的方法是:

var result = new Item { Id = 123, Name = "Hero" };

return new JsonResult(result)
{
    StatusCode = StatusCodes.Status201Created // Status code here 
};
Run Code Online (Sandbox Code Playgroud)

  • 我认为这比@t​​seng的答案要好,因为他的解决方案包括状态代码等重复的字段。 (2认同)
  • 您可以做的一个改进是使用Microsoft.AspNetCore.Http中定义的StatusCodes,如下所示:return new JsonResult(new {}){StatusCode = StatusCodes.Status404NotFound}; (2认同)
  • 这应该是公认的答案。尽管可以通过通用方式设置json,但有时我们必须使用旧式端点,并且设置可能会有所不同。在我们停止支持某些旧式端点之前,这是拥有完全控制权的最终方法 (2认同)

Fab*_*bio 12

这是我最简单的解决方案:

public IActionResult InfoTag()
{
    return Ok(new {name = "Fabio", age = 42, gender = "M"});
}
Run Code Online (Sandbox Code Playgroud)

要么

public IActionResult InfoTag()
{
    return Json(new {name = "Fabio", age = 42, gender = "M"});
}
Run Code Online (Sandbox Code Playgroud)


Oge*_*ike 5

我在这里找到了很棒的答案,我也尝试了这个返回声明,StatusCode(whatever code you wish)它起作用了!

return Ok(new {
                    Token = new JwtSecurityTokenHandler().WriteToken(token),
                    Expiration = token.ValidTo,
                    username = user.FullName,
                    StatusCode = StatusCode(200)
                });
Run Code Online (Sandbox Code Playgroud)