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

Asp.net mvc 如何区分ASP.NET MVC 4控制器中的空模型和初始模型?,asp.net-mvc,asp.net-mvc-4,get,data-annotations,model-binding,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,而不是post(即表单的方法设置为GET) 当我提交表单时没有输入ID(导致URLhttp://..

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

  • 浏览
    http://.../PersonData/Show?id=A5668A31-9AAC-4A14-B471-7C9BA236961D应显示由给定ID标识的人员的数据
  • 浏览
    http://.../PersonData/Show
    应该显示一个带有表单的视图,我可以在其中向文本框中输入ID。当我提交表单时,浏览器应该导航到上面给出的URL,而不是post(即表单的方法设置为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)

我的想法是:

  • 使用两种不同的控制器操作和URL(如
    http://.../PersonData/Search
    http://.../PersonData/Show?id=
    )以区分首次浏览和空表单提交
  • 使用附加的表单参数(如
    http://.../PersonData/Show
    http://.../PersonData/Show?valueGiven=true&id=
  • 使用
    请求
    对象检查操作方法中的URL参数,如果URL中不存在该键,则清除
    模型状态
    错误
解决此问题的最佳/建议方法是什么?有更好的第四种方法吗

(一件不起作用的事情是为GET actions添加两个同名的action方法:

[HttpGet]
public void Show() { /* return view with initial browsing logic */ }
[HttpGet]
public void Show(Model model) { /* return view with subsequent browsing logic */ }
这似乎是ASP.NET MVC不允许的。)

更新2013-06-25:对不起,我的示例中有两个错误,ID应该是
Guid
,而不是字符串;当然,我在action方法中绑定模型是因为我需要计算
Required
属性

这是我的路由配置:

public static void RegisterRoutes (RouteCollection routes)
{
  routes.IgnoreRoute ("{resource}.axd/{*pathInfo}");

  routes.MapRoute (
      name: "Default",
      url: "{controller}/{action}",
      defaults: new { controller = "Home", action = "Index" }
  );
}

若您不传递id,那个么id将为空。如果用值传递id,id将为“”(即,空字符串..string.empty)

因此,您不能使用Required属性,因为这将生成一个错误。您必须手动检查控制器中的值

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

我现在没有能力为您创建和测试这个案例,但这应该会给您一些继续下去的机会。也许其他人可以做点什么

有关路线约束的信息可在此处找到:


如果我将两种方法都作为GET,那么我更喜欢您的第一种方法:搜索页面和带有传入参数的结果页面。如果我想让用户共享链接,我喜欢采用这种方法,因为所有参数都将在querystring中


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

只需在初始显示函数中添加一个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 */
    }
}

你能给我看一下路线配置吗?看起来路由中的ID未设置为可选!这不是我所需要的——我需要区分三种情况:初始浏览、随后使用给定id浏览和随后不使用给定id浏览。(请注意,我原来的问题文本中有两个错误。)@FabianSchmied为什么不对列表使用不同的操作,对create/editSure使用不同的操作,这是我问题的第一个选项:)我只是想看看是否有更好的替代方法。谢谢,你是对的,使用字符串(并省略必需的属性)我可以手动检查。但是,我在原始问题文本中犯了一个错误,实际上有一个
Guid?
——在这种情况下,没有可区分的第三个值(模型绑定器将两个“空”案例绑定到
null
)。省略
RequiredAttribute
意味着我还必须手动附加客户端验证,因此这很不幸(当然可能)。关于路由约束:
id
作为URL参数传递(因为它是一个带有GET方法的HTML表单)。我不能根据一个新的路线创建路线,可以吗?如果是,具体如何?