如何在ASP.NET MVC 4控制器中区分空模型和初始模型?

时间:2013-06-24 15:31:22

标签: asp.net-mvc asp.net-mvc-4 get data-annotations model-binding

在我的ASP.NET MVC应用程序中,我正在尝试实现以下概念:

  • 浏览http://.../PersonData/Show?id=A5668A31-9AAC-4A14-B471-7C9BA236961D应显示由给定ID标识的人员的数据。
  • 浏览http://.../PersonData/Show应显示带有表单的视图,我可以在其中输入ID到文本框中。当我提交表单时,浏览器应导航但不发布到上面给出的URL(即表单的方法设置为GET)。
  • 当我在未输入ID的情况下提交表单(导致浏览URL http://.../PersonData/Show?id=)时,ASP.NET MVC模型验证应显示需要该ID的消息。 (启用或不启用JavaScript。)

为了实现这一点,我构建了一个这样的模型:

class Model
{
  [Required]
  public Guid? Id { get; set; }
}

现在我遇到的问题是,当第一次浏览http://.../PersonData/Show时,ASP.NET模型验证会立即给出一个错误,即ID是必需的,因为它没有区分提交表单的情况一个ID(?id=)以及第一次调用该操作的情况(根本没有给出id)。

我的想法:

  • 使用两种不同的控制器操作和网址(例如http://.../PersonData/Searchhttp://.../PersonData/Show?id=)来区分首次浏览和空表单提交。
  • 使用其他表单参数(例如http://.../PersonData/Showhttp://.../PersonData/Show?valueGiven=true&id=)。
  • 使用Request对象检查操作方法中的网址参数,如果网址中没有该密钥,则清除ModelState的{​​{1}}错误。

解决此问题的最佳/建议方法是什么?有没有更好的第四种方法?

(有一件事不起作用是为GET操作添加两个具有相同名称的操作方法:

"id"

ASP.NET MVC似乎不允许这样做。)

更新2013-06-25:抱歉,我的示例中有两个错误,ID应该是[HttpGet] public void Show() { /* return view with initial browsing logic */ } [HttpGet] public void Show(Model model) { /* return view with subsequent browsing logic */ } ,而不是字符串;当然,我在我的action方法中绑定Model,因为我需要评估Guid属性。

这是我的路由配置:

Required

3 个答案:

答案 0 :(得分:1)

如果你没有传递id,那么id将为null。如果你用一个值传递id,id将是“”(即空字符串.. String.Empty)

因此,您无法使用Required属性,因为这会生成错误。您必须在控制器中手动检查值。

更好的方法是使用路由约束创建一个特殊路由来处理带有id的版本。此路由中的id不是可选的,但约束将阻止不选择不具有id的路由。

我现在没有能力为你创建和测试这个案例,但这应该会给你一些东西。也许其他人可以鞭打一些东西。

路线约束的信息可以在这里找到:

http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-a-route-constraint-cs

答案 1 :(得分:1)

如果我要将这两种方法都作为GET,那么我更喜欢你的第一种方法:搜索页面和传入参数的结果页面。如果我希望用户共享链接,这是我喜欢的方法,因为所有参数都在查询字符串中。

另一方面,如果共享不是真正的问题,我希望有一个GET方法来显示表单,然后将其提交给具有相同名称的action方法的POST版本。

答案 2 :(得分:0)

只需在初始show函数中添加if case

[HttpGet]
public void Show(int? id) {

    if(id.HasValue) {
     /* return view with subsequent browsing logic */ 
    }
    else {
      /* return view with initial browsing logic */
    }
}

编辑: 这可能有用

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

        public RequestMatchAnyAttribute(string matchAnyFormKeys)
        {
            this.MatchFormKey = matchAnyFormKeys;
        }

        public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
        {
            return controllerContext.HttpContext.Request[MatchFormKey] != null;
        }
    }


[HttpGet]
public void Show() {
    /* default view */
}

[ActionName("Show")]
[RequestMatchAny("Id")]
[HttpGet]
public void ShowEdit(int? id) {

    if(id.HasValue) {
     /* return edit view */ 
    }
    else {
      /* return create view */
    }
}