We are working with the MVC 4 Beta. We would like to restrict calls to certain action methods on a controller to Ajax calls; so that browsing to these URLs should return an error.
The code below, which defines an attribute that does just that, used to work in MVC 3.
public class AjaxOnlyAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
return controllerContext.HttpContext.Request.IsAjaxRequest();
}
}
However, this longer works in MVC 4. A breakpoint in the IsValidForRequest does not get hit.
The code is the same except for a slight change: I'm deriving from ApiController, rather than Controller:
public class ServiceController : ApiController
{
This is a MVC 4 web service implementation.
(I do realise that you can use fiddler to make an Ajax call to this service: we just want to prevent users from browsing from the website, as part of creating a restful URL structure.)
Note: Even though Web-Api and MVC4 both have controllers, the implementations have some differences. For example DI out of the box doesn't work on an ApiController. So your situation is a case where the attribute works for MVC controllers, but for whatever
reason it doesn't work with Web-Api controllers (that derive from ApiController).
Currently, Web API contains IActionMethodSelector but unfortunately
it's internal. So, you cannot use action method selector or action name selector in Web API. But you can easily create AjaxOnly, See,
"And whoever is removed away from the Fire and admitted to Paradise, he indeed is successful." (The Holy Quran)
Excellent Windows VPS Hosting Imran Baloch MVP, MVB, MCP, MCTS, MCPD
Marked as answer by Noel Abrahams on Apr 01, 2012 09:16 PM
That's great. Thanks for investigating that - very kind of you. I had to make a slight change to your implementation because the Request no longer contains a CreateReponse method or may be it's an extension method somewhere:
public class AjaxOnlyFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
base.OnActionExecuting(actionContext);
var headers = actionContext.Request.Headers;
if (
!headers.Contains("X-Requested-With") ||
headers.GetValues("X-Requested-With").FirstOrDefault() != "XMLHttpRequest"
)
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
}
}
As you mention, it's also possible to add this globally, since ActionFilterAttribute implements IFilter:
"And whoever is removed away from the Fire and admitted to Paradise, he indeed is successful." (The Holy Quran)
Excellent Windows VPS Hosting Imran Baloch MVP, MVB, MCP, MCTS, MCPD
Marked as answer by ricka6 on Apr 03, 2012 03:28 AM
Noel Abraham...
Member
6 Points
18 Posts
AjaxOnly Attribute for WebAPI
Mar 23, 2012 08:16 PM|LINK
Hi,
We are working with the MVC 4 Beta. We would like to restrict calls to certain action methods on a controller to Ajax calls; so that browsing to these URLs should return an error.
The code below, which defines an attribute that does just that, used to work in MVC 3.
public class AjaxOnlyAttribute : ActionMethodSelectorAttribute { public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) { return controllerContext.HttpContext.Request.IsAjaxRequest(); } }However, this longer works in MVC 4. A breakpoint in the IsValidForRequest does not get hit.
Is there a way to get this working in MVC 4?
Thanks!
ricka6
All-Star
15070 Points
2272 Posts
Microsoft
Moderator
Re: AjaxOnly Attribute for WebAPI
Mar 23, 2012 11:11 PM|LINK
Can you provide me with a trivial repro and I'll investigate? You can email me directly or provide a link.
As far as I know, filter order hasn't changed from MVC 3 to MVC 4.
You do realize it's easy to spoof requests with fiddler or other tools to look like AJAX.
ricka6
All-Star
15070 Points
2272 Posts
Microsoft
Moderator
Re: AjaxOnly Attribute for WebAPI
Mar 23, 2012 11:24 PM|LINK
Your code works for me in MVC 4/Beta
namespace Mvc4TestApp.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; return View(); } [AjaxOnly] public ActionResult About() { ViewBag.Message = "Your quintessential app description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your quintessential contact page."; return View(); } } public class AjaxOnlyAttribute : ActionMethodSelectorAttribute { public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) { return controllerContext.HttpContext.Request.IsAjaxRequest(); } } }Noel Abraham...
Member
6 Points
18 Posts
Re: AjaxOnly Attribute for WebAPI
Mar 25, 2012 10:12 AM|LINK
Hi, Rick,
The code is the same except for a slight change: I'm deriving from ApiController, rather than Controller:
public class ServiceController : ApiController {This is a MVC 4 web service implementation.
(I do realise that you can use fiddler to make an Ajax call to this service: we just want to prevent users from browsing from the website, as part of creating a restful URL structure.)
Thanks for your help.
Noel
ricka6
All-Star
15070 Points
2272 Posts
Microsoft
Moderator
Re: AjaxOnly Attribute for WebAPI
Mar 27, 2012 12:22 AM|LINK
Then it's not a MVC 4 but a WebAPI question.
Noel Abraham...
Member
6 Points
18 Posts
Re: AjaxOnly Attribute for WebAPI
Mar 27, 2012 10:14 AM|LINK
Forgive me for daring to think that the WCF web API has now been integrated into MVC!
CodeHobo
All-Star
18647 Points
2647 Posts
Re: AjaxOnly Attribute for WebAPI
Mar 27, 2012 03:58 PM|LINK
You should probably post your question on the Web-Api forum
http://forums.asp.net/1246.aspx/1?Web+API
Note: Even though Web-Api and MVC4 both have controllers, the implementations have some differences. For example DI out of the box doesn't work on an ApiController. So your situation is a case where the attribute works for MVC controllers, but for whatever reason it doesn't work with Web-Api controllers (that derive from ApiController).
Blog | Twitter : @Hattan
imran_ku07
All-Star
45785 Points
7698 Posts
MVP
Re: AjaxOnly Attribute for WebAPI
Apr 01, 2012 12:14 PM|LINK
Currently, Web API contains IActionMethodSelector but unfortunately it's internal. So, you cannot use action method selector or action name selector in Web API. But you can easily create AjaxOnly, See,
Adding AjaxOnly Filter in ASP.NET Web API
Excellent Windows VPS Hosting
Imran Baloch MVP, MVB, MCP, MCTS, MCPD
Noel Abraham...
Member
6 Points
18 Posts
Re: AjaxOnly Attribute for WebAPI
Apr 01, 2012 09:16 PM|LINK
Hi, Imran,
That's great. Thanks for investigating that - very kind of you. I had to make a slight change to your implementation because the Request no longer contains a CreateReponse method or may be it's an extension method somewhere:
public class AjaxOnlyFilter : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { base.OnActionExecuting(actionContext); var headers = actionContext.Request.Headers; if ( !headers.Contains("X-Requested-With") || headers.GetValues("X-Requested-With").FirstOrDefault() != "XMLHttpRequest" ) actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden); } }As you mention, it's also possible to add this globally, since ActionFilterAttribute implements IFilter:
GlobalConfiguration .Configuration .Filters .Add(new AjaxOnlyFilter());Noel
imran_ku07
All-Star
45785 Points
7698 Posts
MVP
Re: AjaxOnly Attribute for WebAPI
Apr 02, 2012 02:35 AM|LINK
Yes, It's an extension method,
Excellent Windows VPS Hosting
Imran Baloch MVP, MVB, MCP, MCTS, MCPD