ASP.NET MVC: Using ActionMethodSelectorAttribute to Handle Multiple Submit Buttons

Posted by: Malcolm Sheridan , on 6/21/2011, in Category ASP.NET MVC
Views: 116011
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.

 

asp.net mvc form

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.

Action Method Selector Attribute

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.

asp.net mvc post data

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.

asp.net mvc action name

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.

form-value-provider

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.

asp.net-mvc-save-action

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

Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @malcolmsheridan


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by Bill Ramirez on Thursday, June 30, 2011 7:09 PM
I faced this same problem a few days ago and solved it differently, I have to submit buttons, Win and Lose and need to react according.

public class InputForm
{

  public string Win {get;set;}
  public string Lose {get;set;}

  public bool IsWin {
    get {
      return Lose==null;
    }
  }

  // other fields

}

using (Html.BeginForm())
{
<div class="Buttons">
   <input type="submit" value="Win" name="Win" />
   <input type="submit" value="Lose" name="Lose" />
</div>
   .. rest of form fields
}



public ActionResult PostData(Models.Forms.InputForm postData) {
   if (postData.IsWin) {
   } else {
   }
}
Comment posted by Sergey on Tuesday, September 6, 2011 12:12 AM
Here is my solution - https://bitbucket.org/shchegrikovich/multiplesubmitbutton, http://nuget.org/List/Packages/MultipleSubmitButton
Comment posted by millar on Sunday, April 29, 2012 12:01 AM
On my MVC3 razor view I have one "GetRecords" button.Upon clicking this button,it will post back and retrieve multiple sets of records .Depending on the number of record sets it will dynamically regenerate the view and show each set of records.It will also generate "save" and "Delete" buttons against each set of records ,so that the user and review each recordset and can "save" or "delete" data from any of these record sets .

Here my question how to handle button clicks here .Any suggestions

[Httppost]
public ActionResult GetRecords(ContentsViewModel vmodel)
        {
         vmodel.GetRecords();

       return view(vmodel);
     }

Comment posted by anand on Thursday, May 10, 2012 6:48 AM
Why you not permit to copy the code.?????
#&%!$$$$
Comment posted by Admin on Thursday, May 10, 2012 6:50 AM
@anand The entire source code is available to download and use. Why copy it?

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel