In this tutorial, we will explore how to create a formatted response in Controller Action methods. The ASP.NET Core provides several APIs collectively called as Action Results to generate the correctly formatted response, which can be consumed by the Clients. Let us explore what is Action Results are and what are the different types of the Action Results that are available to us
Table of Contents
What is Action Results
The Controller Action methods are expected to return the results to the Client. The Client may expect simple results like string & integers or complex results like Json formatted data, HTML views or a file to download etc.
The Controller in ASP.NET Core is Simple C# Classes. They do not need to inherit from any base classes. The ASP.NET Core provides a Controller base class, which in turn inherits from the ControllerBase Class. This helper class provides a lot of helper methods, which makes the working with Controller easier. Hence, generally, our controllers inherit from the Controller class
The Controller Base class implements various result types out of the box, which helps to build various types of results, which can be sent back to the client. For Example, the ViewResult return the HTML response. A RedirectResult will redirect to another URL etc. The Content Results return a string. These result types are collectively known as Action results.
IActionResult and ActionResult
The IActionResult is an Interface, which defines a contract that represents the result of an action method.
The ActionResult is an Abstract base class which implements IActionResult.
The Action results like ViewResult, PartialViewResult, JsonResult, etc derive from ActionResult base class.
Why Action Results
There is no need to use Action Results in ASP.NET Core. The Controllers are not required to Inherit from the Controller Class. You can directly manipulate HTTP Response object in the Controller to produce the desired result.
The following example shows how to Inject HttpContext object in the Constructor of the Controller and then use it to create a response.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class HomeController { HttpContext ctx; public HomeController(IHttpContextAccessor _ctx) { ctx = _ctx.HttpContext; } public async void Index() { //Set Status Code ctx.Response.StatusCode = 200; //Set Content Type ctx.Response.ContentType = "text/html"; //Create Response ctx.Response.Headers.Add("SomeHeader", "Value"); byte[] content = Encoding.ASCII.GetBytes($"<html><body>Hello World</body></html>"); //Send it to the Client await ctx.Response.Body.WriteAsync(content, 0, content.Length); } } |
Although this approach works, it is not the best way to generate a response from the Controller. The Handling of every controller response this way is tedious, error-prone and difficult to maintain.
The Action Results encapsulate all these low-level details from us. It has many useful features and makes it easier to build responses.
Producing the Response directly in the controller classes, as shown above, makes it hard to Unit Test. To Unit Test of such a controller class, we need to mock the implementations of the Response object. To test the result, we need to Parse the generated HTML Response.
The Action Results eliminates the need to run the controllers and Action methods under the web server. The context objects can be easily mocked through their base classes. You don’t need to parse any HTML to test the result of an action method. You can inspect the ActionResult object that is returned to ensure that you received the expected result.
How to Use Action Results
As mentioned above, the ActionResult is an Abstract base class which implements the IActionResult. This class is defined in the namespace Microsoft.AspNetCore.Mvc.
The ContentResult is one of the Action Results, which returns the string.
1 2 3 4 5 6 7 8 9 10 11 | public class HomeController : Controller { public ContentResult Index() { ContentResult v = new ContentResult(); v.Content = "Hello World"; return v; } } |
The Index method above returns the ContentResult.
We. First instantiate a ContentResult (ContentResult v = new ContentResult();). Next, assign a value to it(v.Content = “Hello World”;). And Finally, return it (return v;)
We have a helper method in the Controller base class, View which does the same thing, but in much simpler way.
1 2 3 4 5 6 | public ContentResult Index() { return Content("Hello"); } |
The Content method invokes the ContentResult internally.
Almost all Action Results have helper method defined in the Controller base class. Usually, these method names have the word “Result” stripped away. For Example Content for ContentResult, View for ViewResult.
The Return Type
The Index method above returns the ContentResult.
The prefered way is to use the ActionResult as the return Type as shown below.
1 2 3 4 5 6 | public ActionResult Index() { return Content("Hello"); } |
Returning the ActionResult instead of the Actual Type, helps us to use the any of the Action Result. Consider the following code snippet.
1 2 3 4 5 6 7 8 9 10 11 | public ActionResult Index(int id) { if (id==0) { return NotFound(); } else { return Content("Hello"); } } |
The Index Action method returns two Action Results. NotFoundResult and ContentResult depending on the value of id parameter.
Action Result Sets
There are many Action Results available in the Microsoft.AspNetCore.Mvc namespace. These can be broadly classified based on their usage as follows.
- Producing the HTML
- Redirecting the Users
- Returning Files
- Content Results
- Returning Errors and HTTP Codes
- Security Related Results
Producing the HTML
There are two Action results, which uses the model to render the HTML Response. ViewResult and PartialViewResult.
ViewResult
The View() method searches for the View in Views/<Controller> folder to locate the .cshtml file and parses it using the Razor view engine. You can also inject the model data into the view. View method returns the ViewResult, which produces the HTML Response.
Open the HomeController and copy the following Code
1 2 3 4 5 6 7 | public ActionResult Index() { var movie = new Movie() { Name = "Avatar" }; return View(movie); } |
The Index method invokes the View() method, which returns the ViewResult.
PartialViewResult
The PartialView Results uses the model to render the part of the View.
We use ViewResult to get the Complete view, the PartialView results return a part of the View. This Result type is useful in Single Page Applications (SPA) where you would like to update a part of the View via an AJAX call.
1 2 3 4 5 6 7 | public ActionResult Index() { var movie = new Movie() { Name = "Avatar" }; return PartialView(movie); } |
Redirecting the Users
The Redirect results are used where you wish to redirect the clients to another URL.
There are four types redirect results are available for use. RedirectResult, LocalRedirectResult, RedirectToActionResult, and RedirectToRouteResult.
Each of these redirects can return any of the following status codes
RedirectResult
The RedirectResult will redirect the user to the provided relative or absolute URL
Action Result | Controller method | Status Code |
---|---|---|
RedirectResult | Redirect | 302 Found (Temporarily moved) |
RedirectPermanent | 301 Moved Permanently | |
RedirectPermanentPreserveMethod | 308 Permanent Redirect | |
RedirectPreserveMethod | 307 Temporary Redirect |
Example:
1 2 3 4 5 6 | Redirect("/Product/Index"); RedirectPermanent("/Product/Index"); RedirectPermanentPreserveMethod("/Product/Index"); RedirectPreserveMethod("/Product/Index"); |
Alternatively, you can use the RedirectResult directly method, which is defined in the microsoft.Aspnetcore.mvc namespace. The syntax is RedirectResult(string url, bool permanent, bool preserveMethod)
1 2 3 | return new RedirectResult(url:"/Product/Index", permanent: true, preserveMethod: true); |
LocalRedirectResult
This action result is similar to the RedirectResult with one exception. Only the local URLs are accepted. If you provide any external URL, this method throws an InvalidOperationException. This action method helps us from the open redirect attacks.
Action Result | Controller method | Status Code |
---|---|---|
LocalRedirectResult | LocalRedirect | 302 Found (Temporarily moved) |
LocalRedirectPermanent | 301 Moved Permanently | |
LocalRedirectPermanentPreserveMethod | 308 Permanent Redirect | |
LocalRedirectPreserveMethod | 307 Temporary Redirect |
Example:
1 2 3 4 5 6 | LocalRedirect("/Product/Index"); LocalRedirectPermanent("/Product/Index"); LocalRedirectPermanentPreserveMethod("/Product/Index"); LocalRedirectPreserveMethod("/Product/Index"); |
RedirectToActionResult
This action result redirects the client to a specific action and controller. It takes in action name, controller name, and route value.
Action Result | Controller method | Status Code |
---|---|---|
RedirectToActionResult | RedirectToAction | 302 Found (Temporarily moved) |
RedirectToActionPermanent | 301 Moved Permanently | |
RedirectToActionPermanentPreserveMethod | 308 Permanent Redirect | |
RedirectToActionPreserveMethod | 307 Temporary Redirect |
Example:
1 2 3 4 5 6 7 | //Redirects to test action in AboutUsController RedirectToAction(actionName: "Index", controllerName: "AboutUs"); //Redirects to Index action in the current Controller RedirectToAction(actionName: "Index"); |
RedirectToRouteResult
This action result redirects the client to a specific route. It takes a route name, route value and redirect us to that route with the route values provided.
Action Result | Controller method | Status Code |
---|---|---|
RedirectToRouteResult | RedirectToRoute | 302 Found (Temporarily moved) |
RedirectToRoutePermanent | 301 Moved Permanently | |
RedirectToRoutePermanentPreserveMethod | 308 Permanent Redirect | |
RedirectToRoutePreserveMethod | 307 Temporary Redirect |
1 2 3 4 5 6 7 8 | // Redirect using route name return RedirectToRoute("default"); //Redirect using Route Value var routeValue = new RouteValueDictionary(new { action = "Index", controller = "Home"}); return RedirectToRoute(routeValue); |
Returning Files
The FileResult is the Action Result uses the Controller action to serve the files to the user.
FileResult
The FileResult Represents a base class that is used to send binary file content to the response. It is an abstract base class, which is implemented by FileContentResult, FileStreamResult, VirtualFileResult, & PhysicalFileResult. These classes take care of the job of returning files to the client.
FileContentResult
The FileContentResult reads from a byte array and returns as a file
1 2 3 | return new FileContentResult(byteArray, "application/pdf") |
FileStreamResult
The FileStreamResult reads from a stream and returns as a file
1 2 3 | return new FileStreamResult(fileStream, "application/pdf"); |
VirtualFileResult
This action result reads the contents of a file from a path relative to the application on the host and sends the contents to the client as a file.
1 2 3 | return new VirtualFileResult("/path/filename", "application/pdf"); |
PhysicalFileResult
This action result reads the contents of a file from a physical location and sends the contents to the client as a file. Note that the path must be an absolute path.
1 2 3 | return new PhysicalFileResult("c:/path/filename", "application/pdf"); |
Content Results
JsonResult
This action result returns the JSON-formatted data. It serializes the given object into JSON and returns it to the client.
1 2 3 4 5 6 7 8 9 10 11 12 13 | public JsonResult About() { return Json(object); } or public JsonResult About() { return new JsonResult(object); } |
ContentResult
The ContentResult writes the specified content directly to the response as plain-text-formatted string data.
1 2 3 4 5 6 7 8 9 10 11 12 13 | public ContentResult About() { return Content("Hello World"); } or public ContentResult About() { return new ContentResult() { Content = "Hello World" }; } |
EmptyResult
The EmptyResult as the name suggests does not return anything. Use this when you want to execute some controller logic, but does not want to return anything
1 2 3 | return new EmptyResult(); |
Returning Errors and HTTP Codes
The Action Results in this section are generally used in Web API controller. These Results sends an HTTP Status Code back to the Client. The some of them can also send an object in the response.
StatusCodeResult
The StatusCodeResult action result sends a specified HTTP status code to the client.
1 2 3 4 5 | return StatusCode(200); or return new StatusCodeResult(200); |
ObjectResult
This action result will use content negotiation to send an object to the client and sets the HTTP 200 status Code. The overload of the StatusCode method can take an object as the second argument and returns an ObjectResult.
1 2 3 4 5 | return StatusCode(200, new { message = "Hello" }); or return new ObjectResult(new { message = "Hello" }); |
Note that the StatusCode controller helper method can send any status code along with an object.
OkResult
This action result sends an HTTP 200 status code to the client.
1 2 3 4 5 | return Ok(); or return new OkResult(); |
OkObjectResult
This action result sends an HTTP 200 status code to the client.
1 2 3 4 5 | return Ok(new {message="Hello"}); or return new OkObjectResult(new { message = "Not found" }); |
CreatedResult
The CreatedResult is used when a Resource is created after a Post Request. This sends the status code 201 along with the object created.
1 2 3 4 5 | return Created(new Uri("/Home/Index", UriKind.Relative), new {message="Hello World"}); or return new CreatedResult(new Uri("/Home/Index", UriKind.Relative), new { message = "Hello World" }); |
CreatedAtActionResult
This Action Result is similar to CreatedResult Action but takes Controller & Action name instead of Uri.
1 2 3 | return CreatedAtAction("Index", new {message="Hello World"}); |
CreatedAtRouteResult
This Action Result takes route values and is similar to CreatedResult and CreatedAtActionResult.
1 2 3 | CreatedAtRoute("default", new { mesage = "Hello World" }); |
BadRequestResult
This action result sends an HTTP 400 status code to the client. Use this response status code to indicate the invalid syntax or request that cannot be understood.
1 2 3 | return BadRequest() |
BadRequestObjectResult
This ActionResult is similar to the BadRequestResult. The difference is that you can send ModelStateDictionary (which is an object containing details of error) along with the 400 status code.
1 2 3 4 5 | var modelState = new ModelStateDictionary(); modelState.AddModelError("message", "errors found. Please rectify before continuing"); return BadRequest(modelState); |
The Controller Helper method BadRequest has a second overload, which returns the BadRequestObjectResult.
NotFoundResult
This Action Result sends an HTTP 404 status code to the client.
1 2 3 | return NotFound(); |
NotFoundObjectResult
This action result is similar to the NotFoundResult, but returns an object along with the 404 status code. The Second overload of NotFound controller helper method takes an object as the argument and returns the NotFoundObjectResult.
1 2 3 | return NotFound( new { message = "Not found" }); |
UnsupportedMediaTypeResult
This action result sends an HTTP 415 status code to the client. Use this action result, when the request is in a format not supported by the server.
1 2 3 | return new UnsupportedMediaTypeResult(); |
NoContentResult
This action result sends an HTTP 204 status code. Use the NoContentResult when the request is fulfilled, but there is no content to send back to the client
1 2 3 | return NoContent(); |
SignInResult
The SignInResult Represents the result of a sign-in operation. The SignInManager.SignInAsync or PasswordSignInAsync returns SignInResult, which has four properties Succeeded, IsLockedOut, IsNotAllowed, and RequiresTwoFactor etc.
You can refer to the ASP.NET Core Identity tutorial
SignOutResult
The SignOutResult Represents the result of a sign-out operation.
ForbidResult
The ForbidResult returns 403 (Forbidden) status code when a user isn’t authorized to perform the requested operation on the given resource.
The ForbidResult does not mean that the user is not authenticated. The unauthenticated users should get ChallengeResult or UnauthorisedResult.
1 2 3 4 5 6 7 | return new ForbidResult(); or return Forbid(); |
The Forbid is a method on the controller base class that returns the instance of the ForbidResult.
Alternatively, you can also use the Status Code result.
1 2 3 | return StatusCode(403); |
ChallengeResult
The ChallengeResult is returned, when the user authentication is failed. This Result will inform any authentication middleware to take the appropriate response, for example returning a 401 (Unauthorized) or 403 (Forbidden) status code, or redirecting the user to a login page for interactive browser clients.
The UnauthorizedResult returns “401 – Unauthorized” HTTP response status code. The Controller base class method Unauthorized returns an instance of UnauthorizedResult.
1 2 3 4 5 6 7 | return Unauthorized(); OR return new UnauthorizedResult(); |
The difference UnauthorisedResult with ChallengeResult is that it just returns a status code and doesn’t do anything else with it.
Summary
In this article, we learnt what is Action Result are and how to use them. We also described most of the action results available in Asp.Net Core.
Very good and helpfull, though i have a question why my SignOutResult geives me CORS issue while ChallengeResult is working fine.
Note: i have application built in .Net Core as rest api and Angular as client side
Great job man, I was looking for that.
Hi. very good article
thanks for sharing keep up the good work
Great article, very relevant information for beginners like me. Thanks very much for sharing. Keep up the great work !
great job sir
keep it up