Is there any attribute relating to AJAX to be set for ASP.NET MVC controller actions?

I want to use partial views with AJAX calls in ASP.NET MVC, and this is the first time I'm using it. I just searched to see if there is anything special I should know beforehand, and one of'em that I'm curious about, is to see if there is any special attribute that should be set or is related to AJAX calls? Something like [ChildActionOnly] or [HttpGet]


Solution 1:

I don't think there is built in attribute for ajax, but you can create your own AjaxOnly filter like this:

public class AjaxOnlyAttribute : ActionMethodSelectorAttribute 
{
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        return controllerContext.RequestContext.HttpContext.Request.IsAjaxRequest();
    }
}

And decorate your action methods like this:

[AjaxOnly]
public ActionResult AjaxMethod()
{
   
}

See Also: ASP.NET MVC Action Filter – Ajax Only Attribute for another way of implementing this

Solution 2:

ASP.NET MVC provides an extension method to check if an Request is an Ajax Request. You can use it to decide if you want to return a partial view or json result instead of a normal view.

if (Request.IsAjaxRequest())
{
    return PartialView("name");
}
return View();

To limit an action method to Ajax calls only you can write a custom attribute. In case of a normal request this filter will return a 404 not found http exception.

[AttributeUsage(AttributeTargets.Method)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
     public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
        if (!filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.HttpContext.Response.StatusCode = 404;
            filterContext.Result = new HttpNotFoundResult();
        }
        else
        {
            base.OnActionExecuting(filterContext);
        }
     }
}

you can use it like that:

[AjaxOnly]
public ActionResult Index() {
    // do something awesome
}

Solution 3:

A spinoff of Muhammad's answer letting you specify that it mustn't be an ajax request as well:

using System.Web.Mvc;
public class AjaxAttribute : ActionMethodSelectorAttribute
{
    public bool ajax { get; set; }
    public AjaxAttribute() { ajax = true; }
    public AjaxAttribute(bool a) { ajax = a; }
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        return ajax == controllerContext.HttpContext.Request.IsAjaxRequest();
    }
}

This lets you do things like...

[Ajax]
public PartialViewResult AjaxUpdatingPage() {
    return PartialView();
}

[Ajax(false)]
public ViewResult NotAjaxUpdatingPage() {
    return View();
}

Update for ASP.NET Core:

You will need to replace the usings and method signature/body with the following...

using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Routing;
using System.Linq;

public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
{
    // Using ASP.NET 6 strongly typed header:
    return ajax == routeContext.HttpContext.Request.Headers.XRequestedWith.Contains("XMLHttpRequest");
    // Older versions:
    return ajax == routeContext.HttpContext.Request.Headers.Any(h => h.Key == "X-Requested-With" && h.Value.Contains("XMLHttpRequest"));
}

Solution 4:

There is an [AjaxOnly] attribute provided in the ASP.NET MVC 3 Futures collection. It's a part of the official ASP.NET MVC Codeplex site that provides features before they are officially included in a future version of ASP.NET MVC.

You can download it here. To use it, add a reference to the Microsoft.Web.Mvc assembly included in the release package.

There is an explanation of the attribute on this page, along with all the other great features you can use.

Solution 5:

For those looking for a .NET Core solution it's a little bit more involved, as IsAjaxRequest() is no longer available.

Below is the code I've used in production on several projects to great effect.

public class AjaxOnlyAttribute : ActionMethodSelectorAttribute
{
  public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor actionDescriptor)
  {
    if(routeContext.HttpContext.Request.Headers != null &&
      routeContext.HttpContext.Request.Headers.ContainsKey("X-Requested-With") &&
      routeContext.HttpContext.Request.Headers.TryGetValue("X-Requested-With", out StringValues requestedWithHeader))
    {
      if(requestedWithHeader.Contains("XMLHttpRequest"))
      {
        return true;
      }
    }

    return false;
  }
}