Action Control in ASP.NET Core

With the release of .NET Core, developers must learn what has changed over classic ASP.NET programming. In this article, Dino Esposito explains that the skills you have will carry over well as he shows how to work with Action Control in ASP.NET Core.

Most of the things that can happen within an ASP.NET MVC and ASP.NET Core application have to do with a controller action method. An action method is only a public method on a controller class. To be precise, it is a public method not marked by the NonAction attribute. Any requesting URL that goes through the ASP.NET routing system—whether template-based routing or attribute routing—identifies a pair made by a controller nickname and an action name. Those two pieces of information are passed to a little known internal component of the ASP.NET MVC application model—the same in classic ASP.NET MVC and ASP.NET Core. It is the Action Invoker component and, as its name clearly suggests, it is responsible for invoking the requested action.

In this article, we’ll first review the overall behavior of the Action Invoker and then focus on the workflow that establishes the data exchange between the invoker and controller classes. Central to this workflow is the action result type and action filters. In the article, we’ll also explore the internals of a custom action result type and a custom action filter.

The Action Invoker

Once the ASP.NET MVC runtime environment has a valid instance of the selected controller class, it yields to the action invoker component for the actual execution of the request. The action invoker gets the action name and attempts to match it to a public method on the controller class. If a method is found and it is not marked with the NonAction attribute, it gets invoked. The action invoker processes the request in two neatly distinct steps. The interesting thing, however, is that the two steps are so tightly bound together that you realize they’re distinct only once you get to learn more about the internals of the MVC application model. In ASP.NET Core, a typical controller method looks like the code below:

In classic ASP.NET MVC, it looks just the same except that the return type is not abstracted to an interface but resorts to the ActionResult base class. Nothing is really different—just one more abstraction layer added. First, the action invoker calls the controller’s action method. The method runs and returns an IActionResult object. It might seem that the action result object is the actual output being returned to the caller, but it is not entirely true. The action result object is returned to the action invoker instead, which then processes it in a second step to generate the content to be written to the response output stream for the caller to receive.

In ASP.NET Core, IActionResult defines the contract that represents the result of an action method. The contract is defined in the code below.

A lot of types in ASP.NET Core implement the IActionResult interface, often through inheritance from the ActionResult base class. At any rate, all action result types must implement a method—the ExecuteResultAsync method—to process the data computed by the controller. The net effect of executing the action result is writing to the output response stream. Let’s consider, for example, the method RedirectToAction as available on the Controller base class. You call the method to redirect the flow to the specified action. The method returns a RedirectToActionResult type. Within the implementation of this type, the ExecuteResultAsync method invokes the Redirect method on the system’s Response object. Similarly, when a controller method terminates with a call to the View method, then the returned action type is ViewResult. When the action invoker executes the view result object, the effect is retrieving the corresponding Razor view, turning its content into an HTML string and writing the HTML string to the response’s output stream.

The Action Result Type

An action method can produce various results. For example, an action method can just act as a web service and return a plain string or a JSON string in response to a request. Likewise, an action method can determine that there’s no content to return or that a redirect to another URL is required. ASP.NET Core provides a variety of concrete action result types, including FileStreamResult, JsonResult, ContentResult and ViewResult. Each action result type is responsible for a specific action. Custom action result types can be created to produce a response that is returned by any of the predefined types. Let’s see an example.

Back in 2015, I wrote an article for Simple-Talk about partial rendering in ASP.NET MVC. In the context of ASP.NET MVC, partial rendering is an unofficial name that refers to the practice of returning a fragment of HTML from a controller method. In this way, by placing an Ajax call via JavaScript, the client page can download an HTML fragment and attach it to the current DOM and refresh the view, without refreshing the full page. In ASP.NET Core, as well as in classic ASP.NET MVC 5.x, you end up with a controller method as shown below:

The pattern works beautifully except that sometimes an action on the client (i.e., clicking to delete an item from a list) needs to refresh two or more fragments of HTML. To avoid making multiple HTTP calls, you need to have a controller method that can return an array of HTML fragments. Unfortunately, this action result type to return an array of HTML fragments didn’t exist in ASP.NET MVC and doesn’t exist in ASP.NET Core. The code I wrote for classic ASP.NET MVC 5.x in that article of 2015 must be slightly revisited because of the new runtime environment in ASP.NET Core. Let’s see what’s different.

Partial Rendering in ASP.NET Core

The following listing shows the full source code of the MultiplePartialViewResult class. The overall workflow of the class is the same as in classic ASP.NET MVC. A few details, though, are different.

The difference with classic ASP.NET MVC is in the way in which the view object is obtained and in how the view is rendered to produce the HTML markup. The key instructions are:

The first line saves a reference to the collection of runtime services. The second line uses the reference to obtain the actual service responsible for executing the PartialViewResult action result type. In other words, in ASP.NET Core there’s a separate layer of code that ‘executes’ action result types. Or, if you prefer, in ASP.NET Core the actual executor code has been abstracted to a contract.

The view is rendered to a view context and the view context contains a buffer where the HTML is accumulated by repeating the process for all the partial views to combine together. Finally, the buffer is flushed to the actual output stream.

The following code demonstrates how to use the MultiplePartialViewResult action result type in a controller class.

The effect of this code is the same as in the old article: a customer is deleted from the database and two HTML fragments are returned, one with the updated list of customers and one with another piece of the user interface to refresh. In the figure below, you see the two segments of the user interface which will be refreshed every time a customer is deleted. The full source code can be found at http://bit.ly/2n1tZtK. The figure below shows the areas of the sample page that must be refreshed when a record in the list is deleted.

Action Filters

An action filter is a piece of code that runs around the execution of an action method and can be used to modify and extend the behavior hardcoded in the method itself. An action filter is fully represented by the following interface:

As you can see, it offers a hook for you to run code before and after the execution of the action. From within the filter, you have access to the request and controller context and can read and modify parameters. Each controller that inherits from the base Controller class gets a default implementation of the IActionFilter interface and exposes two overridable methods called OnActionExecuting and OnActionExecuted. Each controller therefore gives you a chance to decide what to do before and/or after a given method is invoked. Note that this is not true for POCO (plain old CLR object) controllers. In ASP.NET Core, a POCO controller is essentially a controller that doesn’t inherit from the Controller base class.

Action filters are not limited to perform some action only before and/or after a controller method is invoked. What if you want to enable some code to decide whether the method selected to run is fit to serve a given action? For this type of customization, another category of filters is required: action selectors. Action selectors can be of two main types and used to filter the method to select by name and/or by verb. A nice example of this feature is enabling a public method to be invoked only over an Ajax HTTP call.

All you need is a class that inherits from ActionMethodSelectorAttribute and overrides the IsValidForRequest method:

Note that the method IsAjaxRequest is an extension method of the HttpRequest class. Anyway, all that IsAjaxRequest does is checking whether the incoming request brings a specific HTTP header that browsers conventionally add when they implement XMLHttpRequest—the browser component responsible for low level Ajax calls.

In light of this, any controller method marked with the AjaxOnly attribute is only enabled to serve calls placed via the browser’s XMLHttpRequest object.

If you try to invoke a URL that, according to routes, should be mapped to an Ajax-only method, well, you’ll get a not-found exception.

Note that action selectors can be used to check, for example, the user-agent of the requesting client and recognize calls coming from a mobile device. The weirdest use I made of it, however, was to ensure that a given method could be called only within a given time interval of the day—not until 9am and no later than 12pm.

Summary

While ASP.NET Core brings a lot of changes in the runtime pipeline if you choose to build web applications, using the MVC application model the number of changes you face is very limited. The code that governs a controller method call is nearly the same it was in classic ASP.NET MVC except that it relies on a radically different and entirely rewritten runtime pipeline. It comes as no surprise that you still have action filters and can still define custom action result types using the same approach as in the past but facing here and there a few minor changes mostly due to the deep refactoring of the code. In summary, when you approach ASP.NET Core with a solid understanding of classic ASP.NET MVC don’t feel lost—nearly all you know about controllers and actions can be done and nearly in the same way.