正如@timothyclifford提到的,你正在嘗試做的兩件事情在一種形式。在某些情況下,這樣做優先,但對於99%的情況,與第二種形式的鏈接是一種方式。
前一段時間我沒有實現一個動作調用器,它模擬了你正在尋找的功能。它允許您指定您在表單值中指向哪個操作。
它允許您使用幫助選擇過程的屬性標記控制器操作。
我剛剛上傳了一個工作樣本github上:https://github.com/xenolightning/asp-mvc-formaction
FormActionInvoker.cs
/// <summary>
/// Searches the controller for the correct action. Prioritizes FormAction attributed Actions first.
/// Then searches via Method Code
/// </summary>
public class FormActionActionInvoker : AsyncControllerActionInvoker
{
protected override ActionDescriptor FindAction(ControllerContext controllerContext,
ControllerDescriptor controllerDescriptor, string actionName)
{
foreach (var mi in controllerDescriptor.ControllerType.GetMethods())
{
//Searches for the form action attribute first. And if it is present, then it looks
//checks to see if the request is valid. This hpens BEFORE it checks the action name
//which now means ActionName becomes obsolete
var fa =
mi.GetCustomAttributes(false).FirstOrDefault(x => x is FormActionAttribute) as FormActionAttribute;
if (fa == null)
continue;
if (FormActionAttribute.GetAction(controllerContext) != null &&
fa.IsValidForRequest(controllerContext, mi))
return new ReflectedActionDescriptor(mi, actionName, controllerDescriptor);
}
ActionDescriptor ad = base.FindAction(controllerContext, controllerDescriptor, actionName);
var rad = ad as ReflectedActionDescriptor;
if (rad == null)
return ad;
//Here we have to check that the form action attibute isn't in required mode. If it is
//and the form-action is null then we should return null
var formA =
rad.MethodInfo.GetCustomAttributes(false).FirstOrDefault(x => x is FormActionAttribute) as
FormActionAttribute;
if (formA != null && FormActionAttribute.GetAction(controllerContext) == null &&
formA.Mode == FormActionMode.Required)
return null;
return rad;
}
}
FormActionAttribute.cs
/// <summary>
/// When Required the action cannot be invoked unless the form has
/// the required form-action value
/// </summary>
public enum FormActionMode
{
Required,
Normal
}
public class FormActionAttribute : ActionMethodSelectorAttribute
{
public const string HTTP_FORM_NAME = "form-action";
public FormActionAttribute(params string[] values)
: this(FormActionMode.Required, values)
{
}
/// <summary>
/// Constructor to specify the FormActionMode
/// </summary>
/// <param name="mode">
/// Specify Normal to allow invocation of the action with out the matching form action. Defaults to
/// Required
/// </param>
/// <param name="values"></param>
public FormActionAttribute(FormActionMode mode, params string[] values)
{
Values = values;
Mode = mode;
}
public string[] Values
{
get;
private set;
}
public FormActionMode Mode
{
get;
private set;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
string action = GetAction(controllerContext);
if (string.IsNullOrEmpty(action))
return true;
return Values.Any(x => x.Equals(action, StringComparison.CurrentCultureIgnoreCase)) ||
methodInfo.Name.Equals(action, StringComparison.CurrentCultureIgnoreCase);
}
/// <summary>
/// Returns the form action from the current context. Returns null if there is no action
/// </summary>
/// <param name="controllerContext"></param>
/// <returns>Null if there is no action</returns>
internal static string GetAction(ControllerContext controllerContext)
{
string action = controllerContext.HttpContext.Request.Params[HTTP_FORM_NAME];
if (string.IsNullOrEmpty(action))
return null;
//Stops errors on multiple value submissions
//this will choose the first value in the form
if (action.IndexOf(",") > -1)
return action.Split(',')[0];
return action;
}
}
HomeController.cs
public class HomeController : Controller
{
protected override IActionInvoker CreateActionInvoker()
{
return new FormActionActionInvoker();
}
public ActionResult Index()
{
return View();
}
[FormAction]
public ActionResult Login(LoginModel model)
{
return View("Login", model);
}
[FormAction("Forgot")]
public ActionResult DoesntMatterWhatThisIs(LoginModel model)
{
return View("Forgot", model);
}
[FormAction(FormActionMode.Normal)]
public ActionResult Three(LoginModel model)
{
return View("Three", model);
}
}
Index.cshtml
<h2>A Multi Action Form:</h2>
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { @class = "form-horizontal" }))
{
<div class="form-group">
<label for="@Html.IdFor(x => x.Username)" class="col-sm-2 control-label">Username</label>
<div class="col-sm-10">
@Html.TextBoxFor(x => x.Username, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<label for="@Html.IdFor(x => x.Password)" class="col-sm-2 control-label">Password</label>
<div class="col-sm-10">
@Html.PasswordFor(x => x.Password, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-primary" name="form-action" value="Login">Login</button>
<button class="btn btn-primary" name="form-action" value="Forgot">Forgot Password</button>
<button class="btn btn-primary" name="form-action" value="Three">Do Three</button>
</div>
</div>
}
你能張貼在你試圖實現你的鏈接技術的代碼? – Xenolightning
到目前爲止您嘗試了哪些代碼?請發佈視圖和控制器代碼,如果可能的話也發佈視圖模型。 –