AjaxOnly actions and controllers in Asp.Net MVC

Currently as part of my work I find myself doing a lot of client-side work (using the excellent ScriptSharp I might add) and this does involve a lot of calls to the server for bits and pieces via an AJAX call. I’ve decided to dedicate an entire controller to serve such requests.

However, I want to be able to prevent actions on this controller being run from normal requests through the browser. Normally I would just make sure that such requests done through AJAX are through a POST request, but there is a better way.

Inside an action, you can inspect the current HttpContext.Request object and use the handy IsAjaxRequest() extension method to test whether the current request is being executed from an AJAX request or not. You can then just throw an exception if the request isn’t AJAX based when you expect it to be. Performing this in every action would become tiresome though if you have a lot of them. So – you can wrap it up inside a handy Action Filter!

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AjaxOnlyAttribute: ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {  
  if (filterContext.HttpContext.Request.IsAjaxRequest()) {
  } else {
   throw new InvalidOperationException("This operation can only be accessed via Ajax requests");

The code is very simple and really just wraps up code we would otherwise write in each action. Except now you can do this:

public partial class HomeController : Controller {  
  public ActionResult SomeAjaxAction() { 
    return Content("Hello!"); 

Now, if you were to try accessing this action via the browser through the url /Home/SomeAjaxAction, you will hit the exception that is thrown from inside the filter. However, Ajax requests made through jQuery or some other client-side method will pass as normal. Notice how that it doesn’t break the normal GET/POST semantics; we can make Ajax actions which just return some data true Ajax GET requests without worrying about someone inadvertently linking to the action.

You can also mark the controller itself with this attribute so that all the contained actions inherit this behaviour if that is what is required.