是否有一些简单的方法来处理来自同一个表单的多个提交按钮?例如:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>
知道如何在ASP中做到这一点吗?NET框架测试版?我在谷歌上搜索的所有例子中都有单个按钮。
是否有一些简单的方法来处理来自同一个表单的多个提交按钮?例如:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>
知道如何在ASP中做到这一点吗?NET框架测试版?我在谷歌上搜索的所有例子中都有单个按钮。
当前回答
我不喜欢ActionSelectName的地方是IsValidName被控制器中的每个动作方法调用;我不知道为什么会这样。我喜欢一种解决方案,每个按钮都有一个不同的名称,基于它的功能,但我不喜欢这样的事实,你必须有许多参数在动作方法中的按钮在表单。我已经为所有按钮类型创建了一个枚举:
public enum ButtonType
{
Submit,
Cancel,
Delete
}
而不是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;
}
}
}
}
过滤器将在表单数据中找到按钮名称,如果按钮名称与枚举中定义的任何按钮类型匹配,它将在动作参数中找到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)
}
然后在视图中,我可以使用:
<input type="submit" value="Button Cancel" name="@ButtonType.Cancel" />
<input type="submit" value="Button Submit" name="@ButtonType.Submit" />
其他回答
刚刚写了一篇相关的文章: 多个提交按钮与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;
}
}
只需要像这样定义一个表单:
<% using (Html.BeginForm("Action", "Post")) { %>
<!— …form fields… -->
<input type="submit" name="saveDraft" value="Save Draft" />
<input type="submit" name="publish" value="Publish" />
<% } %>
控制器有两个方法
public class PostController : Controller {
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveDraft(…) {
//…
}
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Publish(…) {
//…
}
}
如您所见,该属性根本不需要指定任何内容。此外,按钮的名称直接转换为方法名称。此外(我还没有尝试过)这些应该作为正常的动作以及,所以你可以张贴到他们中的任何一个 直接。
我尝试综合所有的解决方案,并创建了一个[ButtenHandler]属性,它可以很容易地处理表单上的多个按钮。
我已经在CodeProject中描述了它在ASP中的多个参数化(本地化)表单按钮。净MVC。
要处理此按钮的简单情况:
<button type="submit" name="AddDepartment">Add Department</button>
你会有如下的动作方法:
[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
model.Departments.Add(new Department());
return View(model);
}
注意按钮的名称与动作方法的名称是如何匹配的。本文还描述了如何让按钮具有值和按钮具有索引。
给你的提交按钮一个名字,然后在你的控制器方法中检查提交的值:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>
发布到
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"));
}
}
编辑:
要将此方法扩展到本地化站点,请将您的消息隔离在其他地方(例如将资源文件编译为强类型资源类)
然后修改代码,使其像这样工作:
<% 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(); %>
你的控制器应该是这样的:
// 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());
}
这是我发现的最好的方法:
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);
}
}
}
享受一个没有代码气味的多提交按钮的未来。
谢谢你!
有三种方法可以解决上述问题
HTML的方式 Jquery的方式 “ActionNameSelectorAttribute”的方式
下面是一个视频,它以演示的方式总结了所有三种方法。
https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940
HTML方式:-
在HTML中,我们需要创建两个表单,并在每个表单中放置“Submit”按钮。每一种形式的动作都会指向不同的/各自的动作。你可以看到下面的代码,第一个表单发布到“Action1”,第二个表单将发布到“Action2”,这取决于点击哪个“提交”按钮。
<form action="Action1" method=post>
<input type=”submit” name=”Submit1”/>
</form>
<form action="Action2" method=post>
<input type=”submit” name=”Submit2”>
</form>
Ajax方式:-
如果您是Ajax爱好者,那么第二个选项会让您更兴奋。在Ajax中,我们可以创建两个不同的函数“Fun1”和“Fun1”,参见下面的代码。这些函数将使用JQUERY或任何其他框架进行Ajax调用。这些函数都与“Submit”按钮的“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>
使用“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>
因此,当单击提交按钮时,它首先命中“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;
}
}
上述函数的核心在下面的代码中。“ValueProvider”集合包含从表单中发布的所有数据。因此,它首先查找“Name”值,如果在HTTP请求中找到它,则返回true,否则返回false。
var value = controllerContext.Controller.ValueProvider.GetValue(Name);
if (value != null)
{
return true;
}
return false;
然后可以在各自的操作上装饰这个属性类,并提供各自的“Name”值。因此,如果提交正在命中这个动作,如果名称与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");
}
}