We will see how we can involve action selection process in ASP.NET MVC with ActionNameSelectorAttribute with a real world use case scenario.
@ 03-21-2012
by Tugberk Ugurlu


In ASP.NET MVC, out of the box Controller class provides us a nice way to work with the framework. One of the advantages of using this class as a base controller class is that it provides so much nice functionality. One of those is ActionNameSelectorAttribute class.

This class represents an attribute that affects the selection of an action method. ActionNameAttribute class is an implementation of this abstract class and provides an ability to catch requests which comes to a particular action. Here is a sample:

public class HomeController : Controller { 

    [ActionName("FooBar")]
    public ViewResult Foo() { 
    
        return View();
    }
}

We have an action method named Foo and we know that MVC Framework will pick the method which has the same name as the action route parameter. In this case, we expect Foo method to be invoked if we hit /Home/Foo but it is not going to be because we supplied the ActionNameAttribute to involve in the action selection process and tell it to pick actions which has the FooBar value.

You might be using ASP.NET MVC for a while now and have never used this feature so far but sometimes this might come in handy. Here is a weird use case which I needed to implement:

In an application, I made use of new JavaScript pushstate and popstate features but I wanted to gracefully handle this. I implemented some sort of logic at client side and server side. Finally, I got it right but there was a problem:

I have an Index action which excepts all GET and POST requests but I wanted to invoke some other function if the request comes as POST and is an none-ajax request. there are some ways to handle this, just like checking the request method and if the request is an Ajax request but it felt so dirty to me. So, I decided to take advantage of ActionNameSelectorAttribute.

Here is the implementation:

[AttributeUsage(
    AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class NoneAjaxActionNameAttribute : ActionNameSelectorAttribute {

    public NoneAjaxActionNameAttribute(string name) {
        if (String.IsNullOrEmpty(name)) {
            throw new ArgumentException("Name paramater is null", "name");
        }

        Name = name;
    }

    public string Name {
        get;
        private set;
    }

    public override bool IsValidName(ControllerContext controllerContext, 
        string actionName, MethodInfo methodInfo) {

        return 
            String.Equals(actionName, Name, StringComparison.OrdinalIgnoreCase) &&
            !controllerContext.HttpContext.Request.IsAjaxRequest();
    }
}

As you see, it implements the ActionNameSelectorAttribute class and overrides only one method which is IsValidName. Inside that method, we should decide whether the action is in a valid state to be invoked or not. In our case, it checks the action name against the supplied name and if the request is an Ajax request or not.

Her is my controller which made use of this attribute:

public class ContentSearchController : Controller {

    private readonly IContentSearchService _contentSearchService;
    const int pageSize = 10;

    public ContentSearchController(IContentSearchService contentSearchService) {

        _contentSearchService = contentSearchService;
    }

    public ActionResult Index(string q, int page = 1) {

        var model = _contentSearchService.Search(q, page, pageSize);

        if (Request.IsAjaxRequest()) {
        
            return Json(new { 
                    data = this.RenderPartialViewToString("_SearchResult", model) 
            });
        }

        return View(
            model
        );
    }

    [NoneAjaxActionName("Index"), HttpPost]
    public RedirectToRouteResult Index_post(string searchTerm) {

        return RedirectToAction("index", new { q = searchTerm });
    }
}

As you see, I also added HttpPostAttribute to pick only POST requests.

By the help of a little bit of code, we suddenly find ourselves in the middle of action selection process and I think it is pretty powerful even if it’s a cheesy implementation.




Hi 🙋🏻‍♂️ I'm Tugberk Ugurlu.
Coder 👨🏻‍💻, Speaker 🗣, Author 📚, Microsoft MVP 🕸, Blogger 💻, Software Engineering at Deliveroo 🍕🍜🌯, F1 fan 🏎🚀, Loves travelling 🛫🛬
Lives in Cambridge, UK 🏡