Actions in ASP.NET Core

Actions in ASP.NET Core

On my last tutorial on Controllers in ASP.NET Core I tough about Controller. A controller contains Action methods, they can have any return type like string, int, datetime, ViewResult, IActionResult etc. In all of them the return type of IActionResult is quite useful.

When the return type of action method is IActionResult or ViewResult then it can tell MVC to render a given View. This is done by the View() method.

The given action method is telling MVC to return a View which in this case is the Index View.

public IActionResult Index()
{
    return View();
}

The View() method has 4 different versions which are described in the below table:

Method Description
View() Targets the default View for the MVC to render it. Eg if the action method name is List and you are using the View() method then the List.cshtml view will be rendered.
View("name_of_view") This version takes the view name in its parameter and this view will be rendered. Eg if you use View("Show") then the show.cshtml view will be rendered
View(model) This version will render the default view by providing it with model data (class data). This is used to make the rendered view strongly typed.
View("name_of_view", model) This version specifies the View by it’s name along with the model data that it will be provided with.

Passing Data from Action Method to View

There are 4 different ways of passing data from Action Method to a View. These are:

1. View Model Object
2. ViewBag
3. TempData
4. Session Variable

View Model Object

Previously I explained the View() method to you. This method is used to send an object to the View. To understand it, create a new Controller and name it Example and let its Index Action returns current date & time (by DateTime.Now) as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace UnderstandingControllersViews.Controllers
{
    public class ExampleController : Controller
    {
        public IActionResult Index()
        {
            return View(DateTime.Now);
        }
    }
}

I have passed DateTime object to the View. Now create Index View inside the Views ➤ Example folder with the code as given below. Notice I am displaying the date & time value contained in the model like @Model (as it is returned by the Action method).

@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    Model: @Model and Year: @(((DateTime)Model).Date)    
</body>
</html>

Now to display the current Year my code is – @(((DateTime)Model).Date). This is because I have to cast the Model to DateTime first only then I can extract the Date from it.

Run the application and go to – https://localhost:44339/Example. You will see the Date Time and Current Year displayed on the browser as shown in the below image.

untyped view

This is an Untyped View or Weakly Typed View. The View has no prior knowledge about the View Model Object it will be receiving from the Action. So I have to cast it to an instance of DateTime.

I can make this view Strongly Typed View by telling the View the type of the View Model Object it will be receiving from the Action. This is done by adding – @model DateTime

The below highlighted code makes my View strongly typed:

@model DateTime
@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    Model: @Model and Year: @Model.Year
</body>
</html>

Notice I defined the View Model Object by – @model DateTime.

Now I can simply display the current year as – @Model.Year without having to cast it.

In the same way you can also send View Model Object of type String, class, bool, etc.

Note: In the article on Model Binding in ASP.NET Core I explained how to pass class object from Action method to a View.

If you are passing string from action to view then cast your string to Object, like this way:

retrun View((object)"How are you");

The reason for this is because if the parameter of the View() method is a string then it will search for the view with the same name as the provided string. To avoid this thing you need to cast your string to an object.

ViewBag

View Bag allows to define properties on a dynamic object. These properties can then be accessed in Views. This dynamic object can be accessed through the ViewBag property.

Create a new action by name ViewBagExample in the Example Controller having code shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace UnderstandingControllersViews.Controllers
{
    public class ExampleController : Controller
    {
        public IActionResult Index()
        {
            return View(DateTime.Now);
        }

        public IActionResult ViewBagExample()
        {
            ViewBag.CurrentDateTime = DateTime.Now;
            ViewBag.CurrentYear = DateTime.Now.Year;
            return View();
        }
    }
}

I have added 2 properties – CurrentDateTime & CurrentYear to the ViewBag variable. These contains the current datetime and current year.

Now on my View I can simply access these values like ViewBag.CurrentDateTime & ViewBag.CurrentYear. See the below code of the view called ViewBagExample:

@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ViewBagExample</title>
</head>
<body>
    Model: @ViewBag.CurrentDateTime and Year: @ViewBag.CurrentYear
</body>
</html>

Now run the application and go to the URL – https://localhost:44339/Example/ViewBagExample, it will give the same display like before.

untyped view
Points to Remember
  • 1. ViewBag is lightweight method of transferring values to Controllers to Views.
  • 2. ViewBag only transfers data from controller to view, not visa-versa. ViewBag values will be null if redirection occurs.
  • 3. It can contain both primitive or a complex type object.
  • 4. You can assign any number of properties and values to ViewBag.

TempData

You know that ViewBag values are lost in case there is a redirection therefore for such cases you use TempDate. TempData is similar to ViewBag except that its values live during redirection also.

Like ViewBag MVC automatically removes the values of the TempData as soon as they are read.

Let’s add 2 new actions in the Example Controller. These have the names – TempDataExample & TempDataShow. The codes for these 2 actions are given below:

public IActionResult TempDataExample()
{
    TempData["CurrentDateTime"] = DateTime.Now;
    TempData["CurrentYear"] = DateTime.Now.Year;
    return RedirectToAction("TempDataShow");
}
 
public IActionResult TempDataShow()
{
    return View();
}

The action called TempDataExample adds the current datetime and current year to 2 TempDate properties:

  • 1. CurrentDateTime
  • 2. CurrentYear

It then redirects to the TempDataShow action using the RedirectToAction method as shown below:

return RedirectToAction("TempDataShow");

The TempDataShow view just invokes the default View.

Now create the TempDataShow View inside the Views ➤ Example folder. Then add the below code to it:

@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>TempDataShow</title>
</head>
<body>
    Model: @TempData["CurrentDateTime"] and Year: @TempData["CurrentYear"]
</body>
</html>

TempData stores values in dictionary manner so I am accessing these values using brackets ‘[]’.

Note that TempData relies on Session Middleware therefore you have to add services.AddSession() to the ConfigureServices() method of Startup.cs class.

The highlighted lines in the below code tells what you have to add to the Startup class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace UnderstandingControllersViews
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddSession();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //...
        }
    }
}

The AddSession methods create services required by session
management.

Now run the application and go to the URL – https://localhost:44339/Example/TempDataExample, it will show the current datetime and year, like the View Model Object example above.

Note: We can’t use ViewBag in this case as Viewbag values gets lost during redirection. You can check it by replacing the TempData with ViewBag in the TempDataShow View and the TempDataExample action.

MVC automatically removes the values of the TempData as soon as they are read. There is ‘Keep’ method to prevent MVC from removing the value once read. However if the value is read again (2nd time) then MVC will delete it.

The ‘Peek’ method allows you to get the value and also prevent it from deletion. This is because it does not tells MVC that the value has been read.

Use session to store the value permanently (until the session expires) for as many reads as you want and in any part of the application.

Session Variable

Session state is a storage of data while the user browses a website. Session state uses a store maintained by the app to persist data across requests from a client. You can use the data stored in the Session variable anywhere in your website.

You can enable the session for the application by adding services.AddSession() in the ConfigureServices() method and app.UseSession() in the Configure() method of the Startup class. I have highlighted this in the below code:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        services.AddSession();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseSession();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

Let us understand how Session State works. Create a new action called SessionExample inside the Example Controller with codes given below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace UnderstandingControllersViews.Controllers
{
    public class ExampleController : Controller
    {
        // removed for simplicity

        public IActionResult SessionExample()
        {
            HttpContext.Session.SetString("CurrentDateTime", DateTime.Now.ToString());
            HttpContext.Session.SetString("CurrentYear", DateTime.Now.Year.ToString());
            return View();
        }
    }
}

To use session in controller class, you need to reference the Microsoft.AspNetCore.Http namespace in the controller.

The SetString() method will add any value as string to the session variable. In my case I am adding the current datetime and year as string to the 2 session variables.

To access the session’s variable value in the view you have to add a singleton service to the ConfigureServices() method of Startup.cs as shown below

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddSession();
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

Now create the SessionExample View inside the Views ➤ Example folder and add the following code to it:

@using Microsoft.AspNetCore.Http
@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@{
    Layout = null;
}
 
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>SessionExample</title>
</head>
<body>
    Model: @HttpContextAccessor.HttpContext.Session.GetString("CurrentDateTime") and Year: @HttpContextAccessor.HttpContext.Session.GetString("CurrentYear")
</body>
</html>

I have included the namespace Microsoft.AspNetCore.Http just like the controller. Then injected my singleton object through the inject directive using ASP.NET Core Dependency Injection.

Finally I access the session values using @HttpContextAccessor.HttpContext.Session.GetString().

Run the application and go to the URL – https://localhost:44339/Example/SessionExample to see the current datetime and year displayed by the view.

untyped view
More information about Session

Just like the SetString() method the session also has SetInt32() which stores the int value in the session variable:

HttpContext.Session.SetInt32("MySession", 100);

To store complex data types like class variable in the session you have to first serialize them. Then to get the serialized value from session you have to De-serialize them.

To do this add the following extension methods to set and get serializable objects

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;

namespace UnderstandingControllersViews.Models
{
    public static class SessionExtensions
    {
        public static void Set<T>(this ISession session, string key, T value)
        {
            session.SetString(key, JsonConvert.SerializeObject(value));
        }

        public static T Get<T>(this ISession session, string key)
        {
            var value = session.GetString(key);

            return value == null ? default(T) :
                JsonConvert.DeserializeObject<T>(value);
        }
    }
}

Then in your C# code you can do these things:

// Setting the session value
HttpContext.Session.Set<Person>("MyPersonClass", person);
 
// Getting the session value
HttpContext.Session.Get<Person>("MyPersonClass");

Session’s cookie name and expiration time can be set inside the services.AddSession() method as shown below:

services.AddSession(options =>
    {
        options.Cookie.Name = "AdventureWorks.Session"; // Cookie name
        options.IdleTimeout = TimeSpan. FromHours(1); // 1 hours expiry
    });

Performing Redirections in Action Methods

There are many ways to perform redirection from an action method to another action method. There are many methods for it like:

1. Redirect
2. RedirectPermanent
3. RedirectToRoute
4. RedirectToRoutePermanent
5. RedirectToAction
6. RedirectToActionPermanent

Redirect

The Redirect method is used to perform a temporary redirection (HTTP 302). It takes the redirection URL as a string argument and returns an instance of the RedirectResult class.

Example: The below Action method by the name of RedirectAction performs a temporary redirect to URL – /List/Search.

public RedirectResult RedirectAction() => Redirect("/List/Search");

RedirectPermanent

RedirectPermanent method is similar to Redirect method except it redirects user permanently (HTTP 301).

Example: This time the action method by the name of RedirectAction performs a permanent redirect to URL – /List/Search.

public RedirectResult RedirectAction() => RedirectPermanent("/List/Search");

RedirectToRoute

If you want to redirect user by following the routes of your application then you should use RedirectToRoute() method. It performs temporary redirection and takes an anonymous type as parameter. The properties of the anonymous type are then passed to the routing system to generate a URL.

The RedirectToRoute() method returns an instance of the RedirectToRouteResult.

Let’s take an example. My application has the route:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

To perform based on this route I can use the RedirectToRoute() method as shown below:

public RedirectToRouteResult Redirect() {
    RedirectToRoute(new { controller = "Admin", action = "Users", ID = "10" });
}

So it will redirect user to – /Admin/Users/10.

RedirectToRoutePermanent

The RedirectToRoutePermanent similar to RedirectToRoute method except it redirects user permanently.

Example:

public RedirectToRouteResult Redirect() {
    RedirectToRoutePermanent(new { controller = "Admin", action = "Users", ID = "10" });
}

RedirectToAction

The RedirectToAction method performs temporary redirection to a given action method.

This method returns an instance of RedirectToActionResult class.

The redirect URL is formed based on the routes of your application.

Consider that my application route is:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

Now consider you apply RedirectToAction() method on the Index View as shown in the below code:

public class HomeController : Controller
{
    public RedirectToActionResult Index()
    {
        return RedirectToAction("List");
    }
     
    public RedirectToActionResult List()
    {
        return View();
    }
}

So this will redirect user (based on the routes) to the URL – /Home/List.

If you give just an action method, then ASP.NET Core assumed that you are referring to an action method in the current controller.

So to redirect to the action of a different Controller you need to specify the Controller name also. In the below code I am redirecting to the List action of Customer controller:

public RedirectToActionResult Index()
{
    return RedirectToAction("Customer","List");
}

RedirectToActionPermanent

The RedirectToActionPermanent method performs permanent redirection. In all other cases it is similar to RedirectToAction method.

Example:

public RedirectToActionResult Index()
{
    return RedirectToActionPermanent("List");
}

Returning Different Types of Content from Action Methods

So far you have seen Action method returning string and View. But these are not the only things. In fact Actions Methods can return JSON and HTTP Status codes also. The below topics teaches you these methods.

Returning JSON from Action

The method Json() returns JSON (JavaScript Object Notation) objects from Action methods. This method returns an object of JsonResult class.

The action method called ReturnJson located in the ExampleController return a JSON:

public JsonResult ReturnJson()
{
    return Json(new[] { "Brahma", "Vishnu", "Mahesh" });
}

Create the View called ReturnJson.cshtml inside the Views ➤ Example folder and show the JSON with @Model. The full code of this view is given below:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ReturnJson</title>
</head>
<body>
    @Model
</body>
</html>

To test it run the application and go to the URL – https://localhost:44339/Example/ReturnJson. You will see the JSON as shown in the given image:

return json from action

Returning OK (HTTP Status Code 200) from Action

The OK method produces an empty HTTP Status Code 200 responses. It can be used to return objects in common format between the browser and the application with HTTP 200 status code.

The return type of this method is OkObjectResult class.

Example:

public OkObjectResult ReturnOk()
{
    return Ok(new string[] { "Brahma", "Vishnu", "Mahesh" });
}

In the View you can simply show the model data as @Model.

To return just an HTTP 200 status code without any data simply use an empty Ok() method.

Returning BadRequest (400), Unauthorized (401), NotFound (404) status codes from Action

The StatusCode method that resides inside the Microsoft.AspNetCore.Http namespace is used to return any type of status codes like BadRequest, Unauthorized, NotFound, etc.

The return type of this method is StatusCodeResult class of Microsoft.AspNetCore.Mvc namespace.

Example: Returning BadRequest – 400 Status Code
public StatusCodeResult ReturnBadRequst()
{
    return StatusCode(StatusCodes.Status400BadRequest);
}
Example: Returning Unauthorized – 401 Status Code
public StatusCodeResult ReturnUnauthorized()
{
    return StatusCode(StatusCodes.Status401Unauthorized);
}
Example: Returning NotFound – 404 Status Code
public StatusCodeResult ReturnNotFound()
{
    return StatusCode(StatusCodes.Status404NotFound);
    //or return NotFound();
}

You can download the full codes of this tutorial from the below link:

Download

Conclusion

In this tutorial I explained Action Methods and their usage in Controllers. I hope you find it useful.

I will continue with Views in my next tutorial – Views in ASP.NET Core

Share this article -

yogihosting

ABOUT THE AUTHOR

This article has been written by the Technical Staff of YogiHosting. Check out other articles on "ASP.NET Core, jQuery, EF Core, SEO, jQuery, HTML" and more.