Multiple Submit Buttons on an ASP.NET MVC page.


Well, it didn’t take me long to run across something that ASP.NET MVC prevents you from doing… or, as I like to put it, “I BROKE MVC”!

On my very first, very simple, project I needed a page with two submit buttons: a Validate button and a Process button. Yes, I know I could have used ActionLinks, but that is not what I wanted. I wanted buttons.

Fortunately, Andrey Shchekin has a nice solution over on his ashmind blog.

I will reorder the code that Andrey presents so that it makes more sense to my monocellular mind:
First ensure that your form is created with the following:

<% using (Html.BeginForm("Action", "Post")) { %$gt;

This ensures that form will perform an HttpPost back to the server, and tells the server to process this with the action “Action”.

Secondly, the submit buttons can be created like this:

<input type="submit" value="Validate Directories" name="Validate" />
<input type="submit" value="Process Images" name="Process" /

The buttons will submit, but because they are submit buttons and not ActionLinks, they will not provide an action. This is why the form has been coded to to post with an action of “Action”.

Next, Andrey created the following class:

public class HttpParamActionAttribute : ActionNameSelectorAttribute {
    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
        if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
            return true;

        if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
            return false;
        
        var request = controllerContext.RequestContext.HttpContext.Request;
        return request[methodInfo.Name] != null;
    }
}

This class comes into play when the MVC framework method selector is trying to tie the returned action to the controller’s methods. This code will tell the selector that a method decorated with this attribute is a match if either

  • the method name matches the action,
  • or the action is “Action” and the method name can be found in the HttpRequest information return.

Since the submit buttons do not provide an action, but the form does (“Action”), and since the submit button will provide the value of the name parameter in the HttpRequest, we just need to decorate methods that have the same name as the submit buttons and the selector will then execute the method that corresponds to the submit button name.

To decorate the methods we do this in the controller:

    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Validate(…) {
        //…
    }

    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Process(…) {
        //…
    }

(note: the match between the submit button name and the method name is case insensitive)

Thanks Andrey. And thanks to Ted Heatherington for his patience in explaining all this to me.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s