Tomas Aschan
Tomas Aschan

Reputation: 60574

How do the httppost, httpput etc attributes in ASP.NET MVC 2 work?

In ASP.NET MVC 2, a couple of new action filter attributes were introduced, as "shorthand" for attributes in ASP.NET MVC 1; for example, applying the HttpPostAttribute does the same thing as applying [AcceptVerbs(HttpVerbs.Post)] to an action method.

In addition, with the more verbose syntax, it is possible to combine different methods, in order to allow for example both Post and Delete.

Now I'm wondering: how do the new attributes work? If I apply both [HttpPost] and [HttpDelete], will ASP.NET MVC 2 allow both or require both (thus allowing nothing)?

Upvotes: 6

Views: 10883

Answers (4)

Ankur Bulsara
Ankur Bulsara

Reputation: 41

You can use AcceptVerbs for chaining, e.g.:

[AcceptVerbs(HttpVerbs.Get|HttpVerbs.Post)]
public ActionResult Customers() {
}

or

[AcceptVerbs("GET","POST")]
public ActionResult Customers() {
}

Upvotes: 3

tvanfosson
tvanfosson

Reputation: 532455

Looking at the code for ActionMethodSelector, it appears that all action method attributes must return true for IsValidForRequest before that action will be added to the set of possible matching methods. Since it's not possible for HttpPost and HttpDelete to return IsValidForRequest for the same request, I would expect that using both will prevent that action from ever matching any request.

Here's a telling comment from the code:

private static List RunSelectionFilters(...) {
// remove all methods which are opting out of this request
// to opt out, at least one attribute defined on the method must return false

(emphasis mine)

Note that you can still use AcceptVerbs and explicitly OR the verbs if you need to match either.

EDIT -- here's an HttpPostOrDelete attribute for you.

[AttributeUsage( AttributeTargets.Method, AllowMultiple = false, Inherited = false )]
public class HttpPostOrDeleteAttribute : ActionMethodSelectorAttribute
{
    private static readonly AcceptVerbsAttribute _innerPostAttribute = new AcceptVerbsAttribute( HttpVerbs.Post );
    private static readonly AcceptVerbsAttribute _innerDeleteAttribute = new AcceptVerbsAttribute( HttpVerbs.Delete );

    public override bool IsValidForRequest( ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo )
    {
        return _innerDeleteAttribute.IsValidForRequest( controllerContext, methodInfo )
               || _innerPostAttribute.IsValidForRequest( controllerContext, methodInfo );
    }
}

Upvotes: 5

Levi
Levi

Reputation: 32818

All filters in MVC are - without exception - independent of one another. No filter is special-cased anywhere in the MVC framework. This was an intentional design decision so that MVC framework components like the invoker can't "cheat" and treat filters located in the MVC binary any differently than filters that you as an application developer would have written.

So when the invoker sees [HttpGet] and [HttpPost] on the same method, there's no special-casing code to take the union of the two. They're executed independently. And since they can never return true for the same request, [HttpGet, HttpPost] effectively excludes any particular method from being an action method.

Upvotes: 4

Kelsey
Kelsey

Reputation: 47726

If you put [HttpPost] and [HttpDelete] together it will require both (which isn't possible) I think. If you chain [HttpGet] it won't work either, etc...

You can easily test it my just taking an existing [HttpPost] action method and adding [HttpDelete] to it. The post will stop working.

I haven't found any examples where I would need to chain them like your suggesting though.

Upvotes: 0

Related Questions