Action Method Selector in ASP.NET MVC

Posted by: Mahesh Sabnis , on 4/11/2016, in Category ASP.NET MVC
Views: 50673
Abstract: Using the Custom Action method selector in ASP.NET MVC to invoke specific action method based on business need.

The object model provided by ASP.NET MVC is fully extensible using which developers can easily extend the MVC pipeline. We can easily implement custom filters for authentication, logging, exceptions, etc. We can also implement custom Controllers, Views, etc. for extending the MVC object model for our application. These customization features offered by ASP.NET MVC makes it extendible and naturally the first choice technology for modern Web Application development.

The MVC request processing starts from the Controller. This object is responsible for containing various Action Methods which gets executed based on the Action Name specified in the http request. The MVC request processing has a built-in method selector using which the specific action method is invoked using IActionInvoker and is sent for execution. The following diagram explains how the Controller class invokes Action method based on the action attributes.

action-method-processing

 

The MVC Controller class has multiple methods with the same name, in a single MVC Controller class. These action method are applied with Action attributes HttpGet and HttpPost on it. These attributes represents the invocation of the Action method (in our case Create) based on the Http request type i.e. GET and POST. The following diagram explains the behavior of the Action Invoker used by the MVC Controller.

action-execution-invocation

The above diagram provides an in-depth process of an action method invocation. As we know that in MVC, the Route expression contains Controller and ActionName. This means that the action is invoked based on the ActionName using built-in Action Name Selector.

But if the MVC Controller has same action method names (which happens in most of the cases), then the built in ActionMethod selector comes in the picture to invoke an action method based on the Http Request Type e.g. GET or POST. This information is present in the Http Request header. MVC uses the ActionMethodSelectorAttribute class to invoke an action method for execution.

We can implement a custom Action Method Selector class using which we can force the MVC controller to invoke a specific action method based on the Http header value we pass in the Http Request. To demonstrate the implementation, this article provides an easy implementation of executing action method, returning products of specific category mentioned in the Http Header. This can be extended further as per the use case you are working on.

Action Method Selector Implementation

Our example is implemented using the Free Visual Studio 2015 Community Edition.

Step 1: Open Visual Studio and create a new ASP.NET Application of name MVC_CustomActionMethodSelector as shown in the following image

create-aspnet-mvc-project

Click on the OK button. The window shown in the following image will be displayed where we need to select an Empty MVC application

mvc-project

Step 2: In the Models folder of the project, add a new class file of name ModelClasses.cs. In this file add the following code

using System.Collections.Generic;

namespace MVC_CustomActionMethodSelector.Models
{
    public class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public int Price { get; set; }
        public string Category { get; set; }
    }

    public class ElectronicsProductsDatabase : List<Product>
    {
        public ElectronicsProductsDatabase()
        {
            Add(new Product() { ProductId = 1, ProductName = "Desktop", Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 2, ProductName = "Laptop",  Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 3, ProductName = "Router",  Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 4, ProductName = "Mouse",   Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 5, ProductName = "USB HDD", Price = 34000, Category = "Electronics" });
            Add(new Product() { ProductId = 6, ProductName = "LCD",     Price = 34000, Category = "Electronics" });
        }
    }

    public class DataAccessElectronics
    {
        public List<Product> GetDataElectronics()
        {
            return new ElectronicsProductsDatabase();
        }
    }

    public class MechanicalProductsDatabase : List<Product>
    {
        public MechanicalProductsDatabase()
        {
            Add(new Product() { ProductId = 1, ProductName = "JCB", Price = 314000, Category = "Mechanical" });
            Add(new Product() { ProductId = 2, ProductName = "Tractor", Price = 134000, Category = "Mechanical" });
            Add(new Product() { ProductId = 3, ProductName = "Leath Machine", Price = 74000, Category = "Mechanical" });
            Add(new Product() { ProductId = 4, ProductName = "Crusher", Price = 104000, Category = "Mechanical" });
            Add(new Product() { ProductId = 5, ProductName = "Mixer", Price = 143000, Category = "Mechanical" });
        }
    }

    public class DataAccessMechanical
    {
        public List<Product> GetDataMechanical()
        {
            return new MechanicalProductsDatabase();
        }
    }
}

The above code contains following classes

  • Product - This is an entity class containing properties for Product information.
  • ElectronicsProductsDatabase - This class is derived from List<Product> class and contains default data for Electronics products
  • DataAccessElectronics - This class contains method for returning all Electronics products.
  • MechanicalProductsDatabase - This class contains default data for mechanical products.
  • DataAccessMechanical - This class contains method for returning all mechanical products.

Note: In a real-world example, Entity framework can be used here to map with the database server.

Step 3: In the project, add a new folder of name CustomActionMethodSelector. In this folder add a new class file of name MyActionMethodSelector. In this class file add the following code

using System.Reflection;
using System.Web.Mvc;

namespace MVC_CustomActionMethodSelector.CustomActioMethodSelector
{
    public class ElectronicsActionMethodSelectorAttribute : ActionMethodSelectorAttribute
    {
        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            return controllerContext.HttpContext.Request.Headers["P-Electronics"] != null;
        }
    }

    public class MechanicalActionMethodSelectorAttribute : ActionMethodSelectorAttribute
    {
        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            return controllerContext.HttpContext.Request.Headers["P-Mechanical"] != null;
        }
    }
}

The above code has the following classes

· ElectronicsActionMethodSelectorAttribute

  • o This class derives from ActionMethodSelectorAttribute class.
  • o The class overrides the IsValidateForRequest() method. This method accepts the ControllerContext object and MethodInfo object. The ControllerContext represent the current controller context which is loaded in the request processing channel under which the method is executing.
  • o The current implementation of the method verifies if the request header contains P-Electronics: true expression, if yes then the action method on which the ElectronicsActionMethodSelectorAttribute is applied will be executed else it will return 404 error message.

· MechanicalActionMethodSelectorAttribute is same as the above class which checks for the request header value as P-Mechanical: true.

 

Step 4: In Controllers, add a new Empty MVC controller of name ProductController with the following action methods in it.

using System.Web.Mvc;
using MVC_CustomActionMethodSelector.Models;
using MVC_CustomActionMethodSelector.CustomActioMethodSelector;

namespace MVC_CustomActionMethodSelector.Controllers
{
    public class ProductController : Controller
    {
        // GET: Product
        public ActionResult Index()
        {
            return View();
        }

        [ElectronicsActionMethodSelector]
        public ActionResult GetElectronics()
        {
            var ds = new DataAccessElectronics();
            var products = ds.GetDataElectronics();
            return View("IndexElectronics", products);
        }
        [MechanicalActionMethodSelector]
        public ActionResult GetMechanical()
        {ttronutes 
            var ds = new DataAccessMechanical();
            var products = ds.GetDataMechanical();
             return View("IndexMechanical", products);
        }

    }
}

The above code shows GetElectronics() and GetMechanical() action on which ElectronicsActionMethodSelector and MechanicalActionMethodSelector attributes are applied respectively. This means that when we send request to these methods with the header value as P-Electronics and P-Mechanical respectively, these methods will be invoked.

Scaffold views for the above two action methods. i.e. IndexElectronics.cshtml and IndexMechanical.cshtml.

Step 5: Apply breakpoint on GetElectronics and GetMechanical action method and the IsValidForRequest method of the Custom Action method selector class added in Step 3. We will test the application using Fiddler tool

Run the application and in the Composer tab of Fiddler, enter following address

http://localhost:44083/Product/GetElectronics

Click on the Execute button, the Http 404 error will be displayed

error-404

Update the request header by adding P-Electronics: true in Fiddler as shown in the following image

request-header

Click on the Execute button, the code will enter in the debug mode. Check out the header values as shown in the following image

debug

The header value is received as P-Electronics, continue debugging and the GetElectronics() action method will be invoked as shown in the following image

elec-debug

Press F5, the execution will be completed with the following result in the Web View of Fiddler.

result

We have the response View returned.

Conclusion

ASP.NET MVC is a fully extendable web application development framework. The Custom Action method selector provides facility to invoke specific action method based on our business need.

Download the entire source code of this article (Github)

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @maheshdotnet or connect with him on LinkedIn


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!