【问题标题】:.NET MVC4 ActionNameSelectorAttribute multiple buttons within View is not working.NET MVC4 ActionNameSelectorAttribute 视图中的多个按钮不起作用
【发布时间】:2015-06-21 22:57:50
【问题描述】:

我已经阅读了许多关于允许对不同视图按钮执行不同控制器操作的文章。但是,我无法让它工作。

我使用从http://blog.ashmind.com/2010/03/15/multiple-submit-buttons-with-asp-net-mvc-final-solution/ 获得的这个code-sn-p。

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;
    }
}

当我单步执行此代码时,我看到 actionNamemethodInfo.Name 的比较。当整个目的是命名与控制器操作不同的方法时,这些怎么可能相等。

对于行为/功能,true 或 false 的返回值究竟意味着什么?

我应该用“Action”覆盖“fciContactUs”操作吗?

控制器 = "HomeController"

  [HttpParamAction]
  [ActionName("Action")]
  [AcceptVerbs(HttpVerbs.Post)]
  [ValidateInput(false)]
  public ActionResult DoClearForm(fciContactUs p_oRecord)
  {
     return RedirectToAction("fciContactUs");
  }

  [HttpParamAction]
  [ActionName("Action")]
  [AcceptVerbs(HttpVerbs.Post)]
  public ActionResult TrySubmit(fciContactUs p_oRecord)
  {
     // This must be the Submit command.
     if (ModelState.IsValid)
     {  ...etc....} 
  }

视图(视图名称是'fciContactUs')表单开始:

@using (Html.BeginForm("Action", "Home"))  {

视图按钮:

<input type="submit" name="TrySubmit" value="Submit" />
<input type="submit" name="DoClearForm" value="Clear Form" />

此外,IsValidName 方法总是返回 false,并且这些方法永远不会被执行。

我担心操作名称、视图名称、控制器名称、按钮名称和 ActionNameSelectorAttribute 类覆盖存在不一致。

我是 MVC 的新手,这整件事让我很困惑。

任何 cmets 或帮助将不胜感激。

【问题讨论】:

    标签: asp.net-mvc-4 button razor view controller


    【解决方案1】:

    让我们从HttpParamActionAttribute 开始。这继承自ActionNameSelectorAttribute,其中:

    表示影响动作方法选择的属性。

    所以,当应用于一个动作,并且一个请求(get 或 post)进来时,这个属性将被调用来查看这个动作是否确实是正确的动作。

    它通过调用 IsValidName 来确定这一点(有点混乱的方法,最好是 'IsMatchingAction' 或类似的方法)。有效名称:

    确定动作名称在指定的控制器上下文中是否有效。

    带参数:

    controllerContext:控制器上下文
    actionName:动作的名称
    methodInfo:关于动作方法的信息

    取自博文,您可以通过controllerContext 获取请求以及该请求中的所有值。

    如果匹配,则返回 true,如果不是我们要查找的操作,则返回 false

    当它被击中时:

    • actionName = 来自BeginForm 的动作名称,硬编码为“动作”
    • methodInfo = 应用属性的控制器动作(方法),例如TrySubmit

    所以第一次检查:

    if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
        return true;
    

    如果您在 BeginForm 中指定了 Action 以外的其他内容,以便它转到请求的操作(即不是“Action”),这只是一个包罗万象的情况。

    第二次检查检查您是否BeginForm中指定了“操作”

    现在是“聪明”的部分:

    var request = controllerContext.RequestContext.HttpContext.Request;
    return request[methodInfo.Name] != null;
    

    这会检查所有request 参数以查看是否有与控制器操作(方法)匹配的参数。

    当您单击submit 按钮时,该提交按钮的name 会在请求参数中传递

    如果你有:

    <input type="submit" name="TrySubmit" value="Submit" />
    <input type="submit" name="DoClearForm" value="Clear Form" />
    

    如果您点击“提交”,则:

    HttpContext.Request["TrySubmit"] == "Submit"
    HttpContext.Request["DoClearForm"] == null
    

    如果您点击“清除表单”,那么

    HttpContext.Request["TrySubmit"] == null
    HttpContext.Request["DoClearForm"] == "Clear Form"`
    

    不需要实际值(“提交”/“清除表单”),只要它不为空即可。

    所以代码

    request[methodInfo.Name] 
    

    检查请求参数是否存在与当前控制器操作(方法)名称匹配的项目,例如:

    [HttpParamAction]
    public ActionResult DoClearForm() 
    {
    

    回答你的第一个问题:

    我看到了 actionName 与 methodInfo.Name 的比较。当整个目的是命名与控制器操作不同的方法时,这些怎么可能相等。

    BeginForm 未指定Action 并且BeginForm 的操作与controll-action(方法)名称匹配时,第一个比较是覆盖。

    因此,在您的场景中,不,它们不会相等,也不应该相等 - 这是相关的 最后 检查。


    现在的问题是:

    为什么这对你不起作用?

    问题是您的操作名称与预期的操作名称不匹配,因为您有这个:

    [ActionName("Action")]
    

    所以HttpParamAction 属性找到您的控制器动作(方法)并说“使用这个”,但随后 MVC 说,但我正在寻找“动作”而不是“动作”所以我会给你“找不到资源”。我不是它这样做的 100% 原因,但如果你使用 MVC5 Route("Action"),它是一样的 - 它无法找到已经使用属性匹配它的操作。

    如果你删除[ActionName("Action")],那么一切都会好起来的。


    替代方案:如果您删除了前两个检查(如果表单操作 = 控制器操作并且如果表单操作!= "Action")并且只将属性应用于您需要的方法(以及为什么 会你将它应用到其他地方吗?),那么它似乎工作正常。

    现在,我使用 [Route("")] 并进行了更改:

    表格:

    using (Html.BeginForm("", "", FormMethod.Post, ...
    

    控制器:

    [HttpParamAction]
    [HttpPost]
    [Route("")]
    public ActionResult DoClearForm() 
    {
    

    (开头的[HttpGet]也有[Route("")]

    和属性:

    public class HttpParamActionAttribute : ActionNameSelectorAttribute 
    {
        public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) 
        {
            var request = controllerContext.RequestContext.HttpContext.Request;
            return request[methodInfo.Name] != null;
        }
    }
    

    作为替代方案,您的“ClearForm”按钮看起来只是重定向到页面。你可以用一个简单的@Html.ActionLink("Clear Form", "fciContractUS") 和一点 css 让它看起来像一个按钮更容易做到这一点。

    如果您有任何客户端验证(例如必填字段),您也会遇到问题,因为在它们有值之前您将无法“提交”以清除表单。

    【讨论】:

      猜你喜欢
      • 2015-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多