如何在ASP.NET MVC框架中处理多个提交按钮?

Spo*_*ike 719 html c# asp.net-mvc http-post form-submit

是否有一些简单的方法来处理来自同一表单的多个提交按钮?例:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>
Run Code Online (Sandbox Code Playgroud)

知道如何在ASP.NET Framework Beta中执行此操作吗?我用Google搜索的所有示例中都有单个按钮.

mko*_*cki 613

以下是基于Maartin Balliauw的帖子和评论的多重提交按钮问题的基于属性的解决方案.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultipleButtonAttribute : ActionNameSelectorAttribute
{
    public string Name { get; set; }
    public string Argument { get; set; }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var keyValue = string.Format("{0}:{1}", Name, Argument);
        var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
            isValidName = true;
        }

        return isValidName;
    }
}
Run Code Online (Sandbox Code Playgroud)

剃刀:

<form action="" method="post">
 <input type="submit" value="Save" name="action:Save" />
 <input type="submit" value="Cancel" name="action:Cancel" />
</form>
Run Code Online (Sandbox Code Playgroud)

和控制器:

[HttpPost]
[MultipleButton(Name = "action", Argument = "Save")]
public ActionResult Save(MessageModel mm) { ... }

[HttpPost]
[MultipleButton(Name = "action", Argument = "Cancel")]
public ActionResult Cancel(MessageModel mm) { ... }
Run Code Online (Sandbox Code Playgroud)

更新: Razor页面看起来提供了开箱即用的相同功能.对于新的开发,可能更可取.

  • 好方案!比那些得分最高的答案更有用 (17认同)
  • @Shoe - 刚刚发现了类似的事情.如果您使用此方法,请确保显式指定要返回的视图的名称:`return View("Index",viewModel)` (15认同)
  • 这种方法的一个问题是,如果你在模型有错误的情况下尝试"返回View(viewmodel)",它将尝试返回一个名为"Send"的视图或者取决于你的参数名称. (11认同)
  • 只是一个信息,我们需要为MethodInfo添加system.Reflection (4认同)
  • 我发现这个解决方案是使用其他技术的幸福婚姻.工作完美,不会影响本地化. (3认同)
  • Yeaaaaaaaa.适用于MVC 4.5.另一个似乎不起作用.很棒+1 (2认同)

Dyl*_*tie 464

为提交按钮指定名称,然后在控制器方法中检查提交的值:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>
Run Code Online (Sandbox Code Playgroud)

张贴到

public class MyController : Controller {
    public ActionResult MyAction(string submitButton) {
        switch(submitButton) {
            case "Send":
                // delegate sending to another controller action
                return(Send());
            case "Cancel":
                // call another action to perform the cancellation
                return(Cancel());
            default:
                // If they've submitted the form without a submitButton, 
                // just return the view again.
                return(View());
        }
    }

    private ActionResult Cancel() {
        // process the cancellation request here.
        return(View("Cancelled"));
    }

    private ActionResult Send() {
        // perform the actual send operation here.
        return(View("SendConfirmed"));
    }

}
Run Code Online (Sandbox Code Playgroud)

编辑:

要扩展此方法以使用本地化站点,请在其他位置隔离您的消息(例如,将资源文件编译为强类型资源类)

然后修改代码,使其工作方式如下:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="<%= Html.Encode(Resources.Messages.Send)%>" />
<input type="submit" name="submitButton" value="<%=Html.Encode(Resources.Messages.Cancel)%>" />
<% Html.EndForm(); %>
Run Code Online (Sandbox Code Playgroud)

你的控制器应该是这样的:

// Note that the localized resources aren't constants, so 
// we can't use a switch statement.

if (submitButton == Resources.Messages.Send) { 
    // delegate sending to another controller action
    return(Send());

} else if (submitButton == Resources.Messages.Cancel) {
     // call another action to perform the cancellation
     return(Cancel());
}
Run Code Online (Sandbox Code Playgroud)

  • 太糟糕了,你依赖于按钮上显示的文字,这对于多语言用户界面来说有点棘手 (28认同)
  • 你应该使用<button type ="submit"而不是<input type,因为<button类型的值不是文本;).然后你可以这样:<button name ="mySubmitButton"type ="submit"value ="keyValue"> YourButtonText </ button> (10认同)
  • 如何将模型传递给动作而不仅仅是提交值? (4认同)
  • Switch/case仅适用于常量,因此本地化版本不能使用switch/case.您需要切换到if else或其他一些调度方法. (3认同)
  • 如果您使用的是jQuery,请注意不要将按钮命名为"action".它会导致库中发生冲突,从而破坏操作URL. (2认同)
  • -1,在实践中我看到这种方法导致了可怕的代码.首先,你最终会得到硬(呃)跟随逻辑和两个,你最终必须接受每个具体方法所需的每个参数,这导致了一个大规模的方法声明.自定义属性方法是KISS方法!如果您不喜欢自定义属性ASP.NET不适合您... (2认同)

Tre*_*oek 121

您可以检查操作中的名称,但您可能会考虑这是否是一个好的设计.考虑操作的责任并且不要将此设计与按钮名称等UI方面过多地结合在一起是一个好主意.因此,请考虑使用2个表单和2个操作:

<% Html.BeginForm("Send", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<% Html.EndForm(); %>

<% Html.BeginForm("Cancel", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>
Run Code Online (Sandbox Code Playgroud)

此外,在"取消"的情况下,您通常只是不处理表单并转到新的URL.在这种情况下,您根本不需要提交表单,只需要一个链接:

<%=Html.ActionLink("Cancel", "List", "MyController") %>
Run Code Online (Sandbox Code Playgroud)

  • 如果您不需要每个提交按钮的相同表单数据,这是可以的.如果你需要比Dylan Beattie更常见的所有数据,那就是你要走的路.有没有更优雅的方式来做到这一点? (53认同)
  • 当真?除了我之外没有人闻到它吗?! (8认同)
  • 关于视觉演示,在这种情况下如何在"取消"按钮旁边有"发送"按钮? (3认同)

Pab*_*rez 98

Eilon建议你可以这样做:

如果您有多个按钮,则可以通过为每个按钮指定名称来区分它们:

<input type="submit" name="SaveButton" value="Save data" />
<input type="submit" name="CancelButton" value="Cancel and go back to main page" />
Run Code Online (Sandbox Code Playgroud)

在控制器操作方法中,您可以添加以HTML输入标记名称命名的参数:

public ActionResult DoSomeStuff(string saveButton, string
cancelButton, ... other parameters ...)
{ ... }
Run Code Online (Sandbox Code Playgroud)

如果将任何值发布到其中一个参数,则表示该按钮是被单击的按钮.Web浏览器仅发布单击的一个按钮的值.所有其他值将为null.

if (saveButton != null) { /* do save logic */ }
if (cancelButton != null) { /* do cancel logic */ }
Run Code Online (Sandbox Code Playgroud)

我喜欢这个方法,因为它不依赖于提交按钮的value属性,它比分配的名称更有可能更改,并且不需要启用javascript

见:http: //forums.asp.net/p/1369617/2865166.aspx#2865166

  • 如果有人遇到这个老问题,如果你不想使用HTML5 <button>元素,这是最干净的答案.如果您不介意HTML5,请使用带有value属性的<button>. (2认同)

And*_*kin 45

刚写了一篇关于它的帖子: ASP.NET MVC的多个提交按钮:

基本上,ActionMethodSelectorAttribute我正在使用ActionNameSelectorAttribute,而不是使用 ,这使我可以假装动作名称是我想要的.幸运的是,ActionNameSelectorAttribute不只是让我指定操作名称,而是可以选择当前操作是否与请求匹配.

所以有我的课(顺便说一下,我不太喜欢这个名字):

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;
    }
} 
Run Code Online (Sandbox Code Playgroud)

要使用只需定义这样的表单:

<% using (Html.BeginForm("Action", "Post")) { %>
  <!— …form fields… -->
  <input type="submit" name="saveDraft" value="Save Draft" />
  <input type="submit" name="publish" value="Publish" />
<% } %> 
Run Code Online (Sandbox Code Playgroud)

和控制器有两种方法

public class PostController : Controller {
    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SaveDraft(…) {
        //…
    }

    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Publish(…) {
        //…
    } 
}
Run Code Online (Sandbox Code Playgroud)

如您所见,该属性不需要您指定任何内容.此外,按钮的名称将直接转换为方法名称.另外(我还没试过)这些也可以作为正常的动作,所以你可以直接发布到任何一个.


Izm*_*oto 35

我建议有兴趣的人士看看Maarten Balliauw的解决方案.我觉得它非常优雅.

如果链接消失,它将使用MultiButton应用于控制器操作的属性来指示该操作应该与哪个按钮单击相关联.


小智 33

它很短且套房:

这是由Jeroen Dop回答的

<input type="submit" name="submitbutton1" value="submit1" />
<input type="submit" name="submitbutton2" value="submit2" />
Run Code Online (Sandbox Code Playgroud)

并在代码behinde中这样做

 if( Request.Form["submitbutton1"] != null)
{
    // Code for function 1
}
else if(Request.Form["submitButton2"] != null )
{
       // code for function 2
}
Run Code Online (Sandbox Code Playgroud)

祝好运.


Mar*_*ell 21

你应该能够命名按钮并给它们一个值; 然后将此名称映射为操作的参数.或者,使用2个单独的动作链接或2个表单.


Iro*_*net 13

你可以写:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>
Run Code Online (Sandbox Code Playgroud)

然后在页面中检查名称=="发送"或名称=="取消"...


san*_*uro 12

关于ActionSelectName,我不喜欢的是为控制器中的每个操作方法调用IsValidName; 我不知道它为什么会这样.我喜欢一个解决方案,其中每个按钮根据它的作用有不同的名称,但我不喜欢你必须在动作方法中拥有与表单中的按钮一样多的参数.我为所有按钮类型创建了一个枚举:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}
Run Code Online (Sandbox Code Playgroud)

而不是ActionSelectName,我使用ActionFilter:

public class MultipleButtonsEnumAttribute : ActionFilterAttribute
{
    public Type EnumType { get; set; }

    public MultipleButtonsEnumAttribute(Type enumType)
    {
        EnumType = enumType;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        foreach (var key in filterContext.HttpContext.Request.Form.AllKeys)
        {
            if (Enum.IsDefined(EnumType, key))
            {
                var pDesc = filterContext.ActionDescriptor.GetParameters()
                    .FirstOrDefault(x => x.ParameterType == EnumType);
                filterContext.ActionParameters[pDesc.ParameterName] = Enum.Parse(EnumType, key);
                break;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

过滤器将在表单数据中找到按钮名称,如果按钮名称与枚举中定义的任何按钮类型匹配,它将在操作参数中找到ButtonType参数:

[MultipleButtonsEnumAttribute(typeof(ButtonType))]
public ActionResult Manage(ButtonType buttonPressed, ManageViewModel model)
{
    if (button == ButtonType.Cancel)
    {
        return RedirectToAction("Index", "Home");
    }
    //and so on
    return View(model)
}
Run Code Online (Sandbox Code Playgroud)

然后在视图中,我可以使用:

<input type="submit" value="Button Cancel" name="@ButtonType.Cancel" />
<input type="submit" value="Button Submit" name="@ButtonType.Submit" />
Run Code Online (Sandbox Code Playgroud)


小智 11

这对我最有用:

<input type="submit" value="Delete" name="onDelete" />
<input type="submit" value="Save" name="onSave" />


public ActionResult Practice(MyModel model, string onSave, string onDelete)
{
    if (onDelete != null)
    {
        // Delete the object
        ...
        return EmptyResult();
    }

    // Save the object
    ...
    return EmptyResult();
}
Run Code Online (Sandbox Code Playgroud)


Aca*_*uza 9

如果您对HTML 5的使用没有限制,则可以使用<button>带有formaction属性的标记:

<form action="demo_form.asp" method="get">
   First name: <input type="text" name="fname" /><br />
   Last name: <input type="text" name="lname" /><br />
   <button type="submit">Submit</button><br />
   <button type="submit" formaction="demo_admin.asp">Submit as admin</button>
</form>
Run Code Online (Sandbox Code Playgroud)

参考:http://www.w3schools.com/html5/att_button_formaction.asp


小智 9

如果您的浏览器支持输入按钮的属性格式(IE 10+,不确定其他浏览器),则以下内容应该有效:

@using (Html.BeginForm()){
    //put form inputs here

<input id="sendBtn" value="Send" type="submit" formaction="@Url.Action("Name Of Send Action")" />

<input id="cancelBtn" value="Cancel" type="submit" formaction="@Url.Action("Name of Cancel Action") />

}
Run Code Online (Sandbox Code Playgroud)


Tom*_*man 9

我也遇到过这个"问题",但通过添加name属性找到了一个相当合理的解决方案.我记不起在其他语言中遇到这个问题了.

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2

  • ...
  • 如果表单包含多个提交按钮,则只有激活的提交按钮成功.
  • ...

这意味着value可以更改,本地化,国际化以下代码属性,而无需额外的代码检查强类型资源文件或常量.

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="send" value="Send" />
<input type="submit" name="cancel" value="Cancel" />
<input type="submit" name="draft" value="Save as draft" />
<% Html.EndForm(); %>`
Run Code Online (Sandbox Code Playgroud)

在接收端,您只需要检查是否有任何已知的提交类型 null

public ActionResult YourAction(YourModel model) {

    if(Request["send"] != null) {

        // we got a send

    }else if(Request["cancel"]) {

        // we got a cancel, but would you really want to post data for this?

    }else if(Request["draft"]) {

        // we got a draft

    }

}
Run Code Online (Sandbox Code Playgroud)


Shi*_*ala 9

您可以通过三种方式解决上述问题

  1. HTML方式
  2. Jquery的方式
  3. "ActionNameSelectorAttribute"方式

以下是一个视频,以演示的方式总结了所有这三种方法.

https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940

HTML方式: -

在HTML方式中,我们需要创建两个表单,并在每个表单中放置"提交"按钮.每个表单的操作都将指向不同/相应的操作.您可以看到下面的代码,第一个表单发布到"Action1",第二个表单将发布到"Action2",具体取决于单击"提交"按钮.

<form action="Action1" method=post>
<input type=”submit” name=”Submit1”/>
</form>

<form action="Action2" method=post>
<input type=”submit” name=”Submit2”>
</form>
Run Code Online (Sandbox Code Playgroud)

Ajax方式: -

如果你是一个Ajax爱好者,这第二个选项会让你更兴奋.在Ajax方式中,我们可以创建两个不同的函数"Fun1"和"Fun1",请参阅下面的代码.这些函数将使用JQUERY或任何其他框架进行Ajax调用.这些功能中的每一个都与"提交"按钮的"OnClick"事件绑定在一起.这些函数中的每一个都调用各自的动作名称.

<Script language="javascript">
function Fun1()
{
$.post(“/Action1”,null,CallBack1);
}
function Fun2()
{
$.post(“/Action2”,null,CallBack2);
}
</Script>

<form action="/Action1" method=post>
<input type=submit name=sub1 onclick=”Fun2()”/>
</form>
<form action="/Action2" method=post>
<input type=submit name=sub2 onclick=”Fun1()”/>
</form>
Run Code Online (Sandbox Code Playgroud)

使用"ActionNameSelectorAttribute": -

这是一个伟大而干净的选择."ActionNameSelectorAttribute"是一个简单的属性类,我们可以编写决策逻辑,决定可以执行哪个操作.

所以第一件事就是HTML,我们需要在提交按钮上加上适当的名称,以便在服务器上识别它们.

您可以看到我们已将"保存"和"删除"添加到按钮名称中.您还可以注意到我们刚刚将控制器名称"Customer"而不是特定的操作名称放在操作中.我们希望操作名称由"ActionNameSelectorAttribute"决定.

<form action=”Customer” method=post>
<input type=submit value="Save" name="Save" /> <br />
<input type=submit value="Delete" name="Delete"/>
</form>
Run Code Online (Sandbox Code Playgroud)

因此,当单击提交按钮时,它首先点击"ActionNameSelector"属性,然后根据触发的提交,它会调用相应的操作.

在此输入图像描述

所以第一步是创建一个继承自"ActionNameSelectorAttribute"类的类.在这个类中,我们创建了一个简单的属性"Name".

我们还需要覆盖返回true或flase的"IsValidName"函数.这个函数是我们编写逻辑的地方,是否必须执行一个动作.因此,如果此函数返回true,则执行操作,否则执行操作.

public class SubmitButtonSelector : ActionNameSelectorAttribute
    {
        public string Name { get; set; }
        public override bool IsValidName(ControllerContext controllerContext, string actionName, System.Reflection.MethodInfo methodInfo)
        {
            // Try to find out if the name exists in the data sent from form
var value = controllerContext.Controller.ValueProvider.GetValue(Name);
            if (value != null)
            {
                return true;
            }
            return false;

        }
    }
Run Code Online (Sandbox Code Playgroud)

上述函数的主要核心在下面的代码中."ValueProvider"集合包含从表单发布的所有数据.所以它首先查找"Name"值,如果在HTTP请求中找到它,则返回true,否则返回false.

var value = controllerContext.Controller.ValueProvider.GetValue(Name);
if (value != null)
      {
        return true;
      }
      return false;
Run Code Online (Sandbox Code Playgroud)

然后可以在相应的动作上修饰该属性类,并且可以提供相应的"名称"值.因此,如果提交正在执行此操作,并且如果名称与HTML提交按钮名称匹配,则它会进一步执行操作,否则执行操作.

public class CustomerController : Controller
{
        [SubmitButtonSelector(Name="Save")]
        public ActionResult Save()
        {
            return Content("Save Called");
        }
        [SubmitButtonSelector(Name = "Delete")]
        public ActionResult Delete()
        {
            return Content("Delete Called");
        }
}
Run Code Online (Sandbox Code Playgroud)


Saa*_*ail 7

David Findley在他的ASP.Net博客上写了大约3种不同的选项.

阅读同一表格中的文章多个按钮,看看他的解决方案,以及每个按钮的优缺点.恕我直言,他提供了一个非常优雅的解决方案,利用你装饰你的行动的属性.


mli*_*bby 7

这是我使用的技术,我还没有在这里看到它.启动此解决方案的链接(由Saajid Ismail发布)是http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form .aspx).它使Dylan Beattie的答案适应本地化而没有任何问题.

在视图中:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<button name="button" value="send"><%: Resources.Messages.Send %></button>
<button name="button" value="cancel"><%: Resources.Messages.Cancel %></button>
<% Html.EndForm(); %>
Run Code Online (Sandbox Code Playgroud)

在控制器中:

public class MyController : Controller 
{
    public ActionResult MyAction(string button)
    {
         switch(button)
         {
             case "send":
                 this.DoSend();
                 break;
             case "cancel":
                 this.DoCancel();
                 break;
         }
    }
}
Run Code Online (Sandbox Code Playgroud)


Jay*_*ass 7

此脚本允许指定data-form-action属性,该属性将作为所有浏览器中的HTML5格式属性(以不显眼的方式):

$(document).on('click', '[type="submit"][data-form-action]', function(event) {
    var $this = $(this),
    var formAction = $this.attr('data-form-action'),
    $form = $($this.closest('form'));
    $form.attr('action', formAction);             
});
Run Code Online (Sandbox Code Playgroud)

包含该按钮的表单将发布到data-form-action属性中指定的URL:

<button type="submit" data-form-action="different/url">Submit</button>   
Run Code Online (Sandbox Code Playgroud)

这需要jQuery 1.7.对于以前的版本,您应该使用live()而不是on().


Sim*_*ver 6

这是我为处理多个图像和/或文本按钮而编写的扩展方法.

这是图像按钮的HTML:

<input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png" 
       type="image">
Run Code Online (Sandbox Code Playgroud)

或者用于文本提交按钮:

<input type="submit" class="ui-button green" name="Submit_Join" value="Add to cart"  />
<input type="submit" class="ui-button red" name="Submit_Skip" value="Not today"  />
Run Code Online (Sandbox Code Playgroud)

这是您从控制器调用的扩展方法form.GetSubmitButtonName().对于图像按钮,它会查找带有.x(表示单击图像按钮)的表单参数并提取名称.对于常规input按钮,它会查找以...开头的名称,Submit_然后从中提取命令.因为我正在逐渐消除确定"命令"的逻辑,所以您可以在客户端上的图像+文本按钮之间切换,而无需更改服务器端代码.

public static class FormCollectionExtensions
{
    public static string GetSubmitButtonName(this FormCollection formCollection)
    {
        return GetSubmitButtonName(formCollection, true);
    }

    public static string GetSubmitButtonName(this FormCollection formCollection, bool throwOnError)
    {
        var imageButton = formCollection.Keys.OfType<string>().Where(x => x.EndsWith(".x")).SingleOrDefault();
        var textButton = formCollection.Keys.OfType<string>().Where(x => x.StartsWith("Submit_")).SingleOrDefault();

        if (textButton != null)
        {
            return textButton.Substring("Submit_".Length);
        }

        // we got something like AddToCart.x
        if (imageButton != null)
        {
            return imageButton.Substring(0, imageButton.Length - 2);
        }

        if (throwOnError)
        {
            throw new ApplicationException("No button found");
        }
        else
        {
            return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:对于文本按钮,您必须在名称前加上前缀Submit_.我更喜欢这种方式,因为它意味着您可以更改文本(显示)值而无需更改代码.与SELECT元素不同,INPUT按钮只有"值"而没有单独的"文本"属性.我的按钮在不同的上下文中说不同的东西 - 但映射到相同的'命令'.我更喜欢以这种方式提取名称而不是编码== "Add to cart".


小智 6

我没有足够的代表在正确的地方发表评论,但我整天都花在这上面,所以想分享.

在尝试实现"MultipleButtonAttribute"解决方案时ValueProvider.GetValue(keyValue)会错误地返回null.

事实证明,当它应该是4.0(其他程序集是4.0)时,我引用的是System.Web.MVC 3.0版.我不知道为什么我的项目没有正确升级,我没有其他明显的问题.

所以如果你ActionNameSelectorAttribute不工作......检查一下.


Aar*_*don 6

我很晚才参加派对,但是这里......我的实现借鉴了@mkozicki,但需要较少的硬编码字符串才能出错. 需要框架4.5+.实质上,控制器方法名称应该是路由的关键.

标记.必须键入按钮名称"action:[controllerMethodName]"

(注意使用C#6 nameof API,提供特定于类型的引用,以指向您想要调用的控制器方法的名称.

<form>
    ... form fields ....
    <button name="action:@nameof(MyApp.Controllers.MyController.FundDeathStar)" type="submit" formmethod="post">Fund Death Star</button>
    <button name="action:@nameof(MyApp.Controllers.MyController.HireBoba)" type="submit" formmethod="post">Hire Boba Fett</button>
</form>
Run Code Online (Sandbox Code Playgroud)

控制器:

namespace MyApp.Controllers
{
    class MyController
    {    
        [SubmitActionToThisMethod]
        public async Task<ActionResult> FundDeathStar(ImperialModel model)
        {
            await TrainStormTroopers();
            return View();
        }

        [SubmitActionToThisMethod]
        public async Task<ActionResult> HireBoba(ImperialModel model)
        {
            await RepairSlave1();
            return View();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

属性魔术.注意使用CallerMemberName善良.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class SubmitActionToThisMethodAttribute : ActionNameSelectorAttribute
{        
    public SubmitActionToThisMethodAttribute([CallerMemberName]string ControllerMethodName = "")
    {
        controllerMethod = ControllerMethodName;
        actionFormat = string.Concat(actionConstant, ":", controllerMethod);
    }
    const string actionConstant = "action";
    readonly string actionFormat;
    readonly string controllerMethod;

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var value = controllerContext.Controller.ValueProvider.GetValue(actionFormat);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[actionConstant] = controllerMethod;
            isValidName = true;
        }
        return isValidName;
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

这是我找到的最佳方式:

http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html

这是代码:

    /// <summary>
    /// ActionMethodSelector to enable submit buttons to execute specific action methods.
    /// </summary>
    public class AcceptParameterAttribute : ActionMethodSelectorAttribute
   {
        /// <summary>
        /// Gets or sets the value to use to inject the index into
        /// </summary>
       public string TargetArgument { get; set; }

       /// <summary>
       /// Gets or sets the value to use in submit button to identify which method to select. This must be unique in each controller.
       /// </summary>
       public string Action { get; set; }

       /// <summary>
       /// Gets or sets the regular expression to match the action.
       /// </summary>
       public string ActionRegex { get; set; }

       /// <summary>
       /// Determines whether the action method selection is valid for the specified controller context.
       /// </summary>
       /// <param name="controllerContext">The controller context.</param>
       /// <param name="methodInfo">Information about the action method.</param>
       /// <returns>true if the action method selection is valid for the specified controller context; otherwise, false.</returns>
       public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
       {

           if (controllerContext == null)
           {
               throw new ArgumentNullException("controllerContext");
           }

           Func<NameValueCollection> formGetter;
           Func<NameValueCollection> queryStringGetter;

           ValidationUtility.GetUnvalidatedCollections(HttpContext.Current, out formGetter, out queryStringGetter);

           var form = formGetter();
           var queryString = queryStringGetter();

           var req = form.AllKeys.Any() ? form : queryString;

           if (!string.IsNullOrEmpty(this.ActionRegex))
           {
               foreach (var key in req.AllKeys.Where(k => k.StartsWith(Action, true, System.Threading.Thread.CurrentThread.CurrentCulture)))
               {
                   if (key.Contains(":"))
                   {
                       if (key.Split(':').Count() == this.ActionRegex.Split(':').Count())
                       {
                           bool match = false;
                           for (int i = 0; i < key.Split(':').Count(); i++)
                           {
                               if (Regex.IsMatch(key.Split(':')[0], this.ActionRegex.Split(':')[0]))
                               {
                                   match = true;
                               }
                               else
                               {
                                   match = false;
                                   break;
                               }
                           }

                           if (match)
                           {
                               return !string.IsNullOrEmpty(req[key]);
                           }
                       }
                   }
                   else
                   {
                       if (Regex.IsMatch(key, this.Action + this.ActionRegex))
                       {
                           return !string.IsNullOrEmpty(req[key]);
                       }
                   }

               }
               return false;
           }
           else
           {
               return req.AllKeys.Contains(this.Action);
           }
       }
   }
Run Code Online (Sandbox Code Playgroud)

享受无需代码气味的多提交按钮未来.

谢谢


cod*_*ner 5

我试图对所有解决方案进行综合,并创建了一个[ButtenHandler]属性,可以轻松处理表单上的多个按钮.

在ASP.NET MVC中的 CodeProject 多参数化(可本地化)表单按钮上进行了描述.

要处理此按钮的简单情况:

<button type="submit" name="AddDepartment">Add Department</button>
Run Code Online (Sandbox Code Playgroud)

您将拥有类似以下操作方法的内容:

[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
    model.Departments.Add(new Department());
    return View(model);
}
Run Code Online (Sandbox Code Playgroud)

请注意按钮的名称与操作方法的名称是否匹配.本文还介绍了如何使用带有索引的值和按钮的按钮.


SHA*_*NGH 5

//model
    public class input_element
        {
         public string Btn { get; set; }
        }   

//views--submit btn can be input type also...
    @using (Html.BeginForm())
    {
            <button type="submit" name="btn" value="verify">
             Verify data</button>
            <button type="submit" name="btn" value="save">
             Save data</button>    
            <button type="submit" name="btn" value="redirect">
                 Redirect</button>
    }

//controller

    public ActionResult About()
        {
            ViewBag.Message = "Your app description page.";
            return View();
        }

        [HttpPost]
        public ActionResult About(input_element model)
        {
                if (model.Btn == "verify")
                {
                // the Verify button was clicked
                }
                else if (model.Btn == "save")
                {
                // the Save button was clicked
                } 
                else if (model.Btn == "redirect")
                {
                // the Redirect button was clicked
                } 
                return View();
        }
Run Code Online (Sandbox Code Playgroud)

  • 此外,您似乎发布只包含代码的答案,没有任何解释.您是否会考虑添加一些叙述来解释代码的工作原理,以及是什么使它成为问题的答案?这对提出问题的人以及其他任何人来说非常有帮助. (2认同)
  • 当然,它工作正常.但很久以前,这个答案已经由其他人*给出了.他们还包括关于*为什么*它的工作原理的解释. (2认同)

Mah*_*dra 5

[HttpPost]
public ActionResult ConfirmMobile(string nameValueResend, string nameValueSubmit, RegisterModel model)
    {
        var button = nameValueResend ?? nameValueSubmit;
        if (button == "Resend")
        {

        }
        else
        {

        }
    }


    Razor file Content:
    @using (Html.BeginForm()
    {
        <div class="page registration-result-page">

            <div class="page-title">
                <h1> Confirm Mobile Number</h1>
            </div>

            <div class="result">
                @Html.EditorFor(model => model.VefificationCode)
                @Html.LabelFor(model => model.VefificationCode, new { })
                @Html.ValidationMessageFor(model => model.VefificationCode)
            </div>
            <div class="buttons">
                <button type="submit" class="btn" name="nameValueResend" value="Resend">
                    Resend
                </button>
                <button type="submit" class="btn" name="nameValueSubmit" value="Verify">
                    Submit
                </button>

            </div>
            </div>

    }
Run Code Online (Sandbox Code Playgroud)