ASP.NET MVC: Using ActionMethodSelectorAttribute to Handle Multiple Submit Buttons
Posted by: Malcolm Sheridan ,
on 6/21/2011,
in
Category ASP.NET MVC
Abstract: The following article demonstrates how to use the ActionMethodSelectorAttribute object to handle multiple submit buttons with ASP.NET MVC.
My first article in this series focused on how to have Multiple submit buttons in the same ASP.NET MVC form, and how to differentiate them in your action method. If you missed it you can read it here. The second part focused on how to do this with Ajax. If you want to hijack your form and post it via Ajax, you need to do some extra work. Controls that have a name attribute are posted as part of the form because they’re a successful control. However when you use Ajax to post a form, only successful controls are serialized into string. Submit buttons aren’t serialized seeing as though the form wasn’t submitted using a button.
To take this example to the next level, I’m removing the if/else logic from the action and am placing all of that logic into an action filter that inherits from the ActionMethodSelectorAttribute. I did an article on using this class here. It showed you how to restrict access to actions. Well this is what I’m going to do in this example.
I’m using the same form as I used in the previous articles.
I’ll start off with the attribute I will decorate my actions with. I’m creating a class that inherits from ActionMethodSelectorAttribute. The first parameter is ControllerContext. This parameter will contain, amongst other objects, the FormValueProvider object. This contains values posted in the form in a NameValueCollection object. This is what I’ll check to see which button submitted the form. Here’s the code below. Nice and compact.
The next step is to create two action methods, Save and Delete. To ensure that either of these actions will be invoked, I’m going to decorate them with the ActionName attribute. This gives you the flexibility of having different actions but still allowing you to access them with a common name. The common name is PostData.
If you tried running the website now, you’ll see this error:
System.Reflection.AmbiguousMatchException: The current request for action 'PostData' on controller type 'HomeController' is ambiguous between the following action methods.
This is because we have two actions decorated with the same ActionName. That isn’t allowed. We need to restrict access to one action only, and we’ll use the ButtonAttribute class for this. I want to decorate my actions with this attribute and supply a ButtonName.
Because this attribute will be executed before the action, it can check the values in the FormValueProvider and see if they match the value specified on the attribute. If posted form contains a value that matches the value in ButtonName, IsValidForRequest returns true, thus the proper action will be invoked.
When the Save button is clicked, a new hidden input named Save will be injected into the form and that will be sent in the forms collection. This is why when you click on the Save submit button, you’ll be directed to the Save action. The same rule applies for the Delete submit button. Here’s the JavaScript to do this.
It’s important to remember that injecting the hidden inputs is not required if the form is submitted without JavaScript. This is another good example of when to use ActionMethodSelectorAttribute.
The entire source code of this article can be downloaded over here
Was this article worth reading? Share it with fellow developers too. Thanks!