ASP.NET Core return JSON with status code
Solution 1
The most basic version responding with a JsonResult
is:
// GET: api/authors
[HttpGet]
public JsonResult Get()
{
return Json(_authorRepository.List());
}
However, this isn't going to help with your issue because you can't explicitly deal with your own response code.
The way to get control over the status results, is you need to return a
ActionResult
which is where you can then take advantage of theStatusCodeResult
type.
for example:
// 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);
}
Note both of these above examples came from a great guide available from Microsoft Documentation: Formatting Response Data
Extra Stuff
The issue I come across quite often is that I wanted more granular control over my WebAPI rather than just go with the defaults configuration from the "New Project" template in VS.
Let's make sure you have some of the basics down...
Step 1: Configure your Service
In order to get your ASP.NET Core WebAPI to respond with a JSON Serialized Object along full control of the status code, you should start off by making sure that you have included the AddMvc()
service in your ConfigureServices
method usually found in Startup.cs
.
It's important to note that
AddMvc()
will automatically include the Input/Output Formatter for JSON along with responding to other request types.
If your project requires full control and you want to strictly define your services, such as how your WebAPI will behave to various request types including application/json
and not respond to other request types (such as a standard browser request), you can define it manually with the following code:
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)
}
You will notice that I have also included a way for you to add your own custom Input/Output formatters, in the event you may want to respond to another serialization format (protobuf, thrift, etc).
The chunk of code above is mostly a duplicate of the AddMvc()
method. However, we are implementing each "default" service on our own by defining each and every service instead of going with the pre-shipped one with the template. I have added the repository link in the code block, or you can check out AddMvc()
from the GitHub repository..
Note that there are some guides that will try to solve this by "undoing" the defaults, rather than just not implementing it in the first place... If you factor in that we're now working with Open Source, this is redundant work, bad code and frankly an old habit that will disappear soon.
Step 2: Create a Controller
I'm going to show you a really straight-forward one just to get your question sorted.
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();
}
}
Step 3: Check your Content-Type
and Accept
You need to make sure that your Content-Type
and Accept
headers in your request are set properly. In your case (JSON), you will want to set it up to be application/json
.
If you want your WebAPI to respond as JSON as default, regardless of what the request header is specifying you can do that in a couple ways.
Way 1 As shown in the article I recommended earlier (Formatting Response Data) you could force a particular format at the Controller/Action level. I personally don't like this approach... but here it is for completeness:
Forcing a Particular Format If you would like to restrict the response formats for a specific action you can, you can apply the [Produces] filter. The [Produces] filter specifies the response formats for a specific action (or controller). Like most Filters, this can be applied at the action, controller, or global scope.
[Produces("application/json")] public class AuthorsController
The
[Produces]
filter will force all actions within theAuthorsController
to return JSON-formatted responses, even if other formatters were configured for the application and the client provided anAccept
header requesting a different, available format.
Way 2 My preferred method is for the WebAPI to respond to all requests with the format requested. However, in the event that it doesn't accept the requested format, then fall-back to a default (ie. JSON)
First, you'll need to register that in your options (we need to rework the default behavior, as noted earlier)
options.RespectBrowserAcceptHeader = true; // false by default
Finally, by simply re-ordering the list of the formatters that were defined in the services builder, the web host will default to the formatter you position at the top of the list (ie position 0).
More information can be found in this .NET Web Development and Tools Blog entry
Solution 2
You have predefined methods for most common status codes.
-
Ok(result)
returns200
with response -
CreatedAtRoute
returns201
+ new resource URL -
NotFound
returns404
-
BadRequest
returns400
etc.
See BaseController.cs
and Controller.cs
for a list of all methods.
But if you really insist you can use StatusCode
to set a custom code, but you really shouldn't as it makes code less readable and you'll have to repeat code to set headers (like for CreatedAtRoute
).
public ActionResult IsAuthenticated()
{
return StatusCode(200, "123");
}
Solution 3
With ASP.NET Core 2.0, the ideal way to return object from Web API
(which is unified with MVC and uses same base class Controller
) is
public IActionResult Get()
{
return new OkObjectResult(new Item { Id = 123, Name = "Hero" });
}
Notice that
- It returns with
200 OK
status code (it's anOk
type ofObjectResult
) - It does content negotiation, i.e. it'll return based on
Accept
header in request. IfAccept: application/xml
is sent in request, it'll return asXML
. If nothing is sent,JSON
is default.
If it needs to send with specific status code, use ObjectResult
or StatusCode
instead. Both does the same thing, and supports content negotiation.
return new ObjectResult(new Item { Id = 123, Name = "Hero" }) { StatusCode = 200 };
return StatusCode( 200, new Item { Id = 123, Name = "Hero" });
or even more fine grained with ObjectResult:
Microsoft.AspNetCore.Mvc.Formatters.MediaTypeCollection myContentTypes = new Microsoft.AspNetCore.Mvc.Formatters.MediaTypeCollection { System.Net.Mime.MediaTypeNames.Application.Json };
String hardCodedJson = "{\"Id\":\"123\",\"DateOfRegistration\":\"2012-10-21T00:00:00+05:30\",\"Status\":0}";
return new ObjectResult(hardCodedJson) { StatusCode = 200, ContentTypes = myContentTypes };
If you specifically want to return as JSON, there are couple of ways
//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" };
}
Notice that
- Both enforces
JSON
in two different ways. - Both ignores content negotiation.
- First method enforces JSON with specific serializer
Json(object)
. - Second method does the same by using
Produces()
attribute (which is aResultFilter
) withcontentType = application/json
Read more about them in the official docs. Learn about filters here.
The simple model class that is used in the samples
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
Solution 4
The easiest way I came up with is :
var result = new Item { Id = 123, Name = "Hero" };
return new JsonResult(result)
{
StatusCode = StatusCodes.Status201Created // Status code here
};
Solution 5
This is my easiest solution:
public IActionResult InfoTag()
{
return Ok(new {name = "Fabio", age = 42, gender = "M"});
}
or
public IActionResult InfoTag()
{
return Json(new {name = "Fabio", age = 42, gender = "M"});
}
Related videos on Youtube
Rossco
Updated on February 23, 2021Comments
-
Rossco about 3 years
I'm looking for the correct way to return JSON with a HTTP status code in my .NET Core Web API controller. I use to use it like this:
public IHttpActionResult GetResourceData() { return this.Content(HttpStatusCode.OK, new { response = "Hello"}); }
This was in a 4.6 MVC application but now with .NET Core I don't seem to have this
IHttpActionResult
I haveActionResult
and using like this:public ActionResult IsAuthenticated() { return Ok(Json("123")); }
But the response from the server is weird, as in the image below:
I just want the Web API controller to return JSON with a HTTP status code like I did in Web API 2.
-
Tseng about 7 yearsThe "ok" methods return 200 as status code. The predefined methods cover all the common cases. To Return 201 (+header with new resource location), you use
CreatedAtRoute
method etc.
-
-
Rossco about 7 yearsThanx so much for the effort you put in. Your answer inspired me to implement
IActionResult
with thereturn Ok(new {response = "123"});
Cheers! -
Svek about 7 years@Rossco No problem. Hopefully the rest of the code will help guide you as your project develops.
-
Svek about 7 yearsTo extend this topic, I created an additional and more complete guide to implementing the WebAPI here: stackoverflow.com/q/42365275/3645638
-
Yishai Galatzer almost 7 yearsOn setting: RespectBrowserAcceptHeader = true; You are not explaining why you are doing it, and it is typically unnecessary and wrong to do so. Browsers ask for html, and hence they shouldn't affect formatter selection in anyway (that chrome unfortunately does by asking for XML). In short it's something I would keep off, and the fallback you are specifying is already the default behavior
-
Svek almost 7 years@YishaiGalatzer The main theme of that part of my answer was to highlight how to unburden the default middleware between the client and the API logic. In my opinion,
RespectBrowserAcceptHeader
is critical when implementing use of an alternative serializer or more commonly, when you want to make sure that your clients are not sending malformed requests. Hence, I emphasized "If your project requires full control and you want to strictly define your service" and note the highlighted block quote above that statement too. -
Phillip Copley over 6 yearsNo. This is bad.
-
Christian Sauer over 6 yearsI think this is better than the answer from @tseng because his solution includes duplicated fields for Status Codes etc.
-
netfed about 6 yearsThis is a good answer because it focuses on the question and explains some practicalities in brief.
-
Bryan Bedard almost 6 yearsOne improvement you can make is to use the StatusCodes defined in Microsoft.AspNetCore.Http like this: return new JsonResult(new { }) { StatusCode = StatusCodes.Status404NotFound };
-
Jari Turkia over 5 yearsAn option: Return JSON with anonymous type. Like this:
JsonResult({status = "ok", result = "good"})
-
Mayer Spitz over 5 yearsI think that in net Core, you don't have the Json() method built in, instead I'm using
JsonResult
-
Lapenkov Vladimir over 5 yearsoptions.RespectBrowserAcceptHeader = true; works as needed
-
pqsk about 5 yearsThis should be the accepted answer. Although there are ways to universally setup the json, sometimes we have to work with legacy endpoints and the settings can be different. Until we can stop supporting some legacy endpoints, this is the ultimate way to have full control
-
Bhimbim about 5 yearsEnum is a great idea !.
-
Chsiom Nwike almost 5 yearsthis gave me insight to my response below. Thank you
-
amedina over 4 yearsThis code isn't correct for ASP.NET Core 2.2. I just have tried it and it serializes into
JSON
theActionResult
created by theJson()
method. It doesn't include the "123" string directly. -
Tseng over 4 years@amedina: My bad, just remove the
Json(...)
and pass the string toStatusCode
-
variable over 4 yearsWhen you say "Ok(result)" - what is result? Is it a JSON format string or is it an C# object (that automatically gets converted to JSON string?)?
-
variable over 4 years@Rossco - when you say "return Ok(new {response = "123"});", does the framework automatically convert the C# object {response = "123"} into JSON string?
-
Rossco over 4 years@variable yes it does
-
Tseng over 4 years@variable: Always a POCO/class/object. If you want return a string, you need to use "Content" instead
-
granadaCoder about 4 yearsMicrosoft.AspNetCore.Mvc.JsonResult is the fully qualified name I think. No FQN or "using" answers drive me nutso. :) Assembly Microsoft.AspNetCore.Mvc.Core, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 // C:\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\3.1.0\ref\netcoreapp3.1\Microsoft.AspNetCore.Mvc.Core.dll
-
granadaCoder about 4 yearsThis worked for me when I had a strong type ("ITem result = new Item" in this example...Item is a known type at runtime)) . See my answer (to this question) for when the type is ~not~ known. (I had json in a db..and the json type was not known at runtime). Thanks Gerald.
-
ticky about 4 yearsLike this one! Good suggestion!
-
toha over 2 yearsHow to route using Post method brother?
-
toha over 2 yearsI mean this snippet : [HttpPost("AsJson")] my brother,, thanks
-
Shane over 2 yearsThe "hardcoded json" example didn't work for me. It was parsing the string as JSON and returning me the string with double quotes (") around it with the json characters escaped. So instead of ObjectResult, I used ContentResult as follows: return new ContentResult() { Content = hardCodedJson, StatusCode = (int)HttpStatusCode.OK, ContentType = "application/json" };
-
user160357 about 2 years[Produces("application/json")] works with .NET 6 in Azure Functions V4
-
AbeyMarquez about 2 yearsThis is the best answer because it does not assume that the OP only needs to return JSON data or only needs custom HTTP codes. And he provides all default and custom options.