【问题标题】:Default value for ViewModelViewModel 的默认值
【发布时间】:2016-10-18 13:52:50
【问题描述】:

我正在 MVC 中制作一个简单的 搜索 页面,其中包含一些过滤器。过滤器由我的 ViewModel 中的属性表示。我的 ViewModel 绑定到 cshtml 中的 GET 表单,因此我的过滤器将出现在查询字符串中,并且用户将能够为他的搜索添加书签。

我想做的是为我的一些过滤器分配一个默认值。

我的(简化的)视图模型:

public class SearchViewModel
{
    //Filter I want to set a default value to
    public OrganizationType? OrganizationType {get; set;}

    //Results of the search
    public IEnumerable<ItemViewModel> Items {get; set;}
}

我想为 OrganizationType 设置一个默认值。我不能简单地在 SearchViewModel 的构造函数中设置它,因为它取决于当前用户:

public void InitViewModel(SearchViewModel vm)
{
    vm.OrganizationType = _someLogic.GetDefaultValue(_currentUser);
}

第一个解决方案是简单地检查 OrganizationType 是否为空,然后分配一个默认值:

public ActionResult Search(SearchViewModel vm)
{
    if(vm.OrganizationType == null)
        vm.OrganizationType = _someLogic.GetDefaultValue(_currentUser);

    return View(vm);
}

但此解决方案不起作用,因为 null 值对应于空过滤器,这是用户可以做出的选择。所以我不能覆盖它。

我尝试的第二个解决方案是在 Search 操作中指定控制器的默认值应为 null:

public ActionResult Search(SearchViewModel vm = null)
{
    if (vm == null) 
    {
        vm = new SearchViewModel();
        InitViewModel(vm);
    }       
    ...

    return View(vm);
}

但实际上,变量 vm 永远不会为空,因此永远不会设置默认值。

我还尝试了两个动作,一个没有 ViewModel,我用默认值实例化一个新的 ViewModel,然后调用第二个动作:

public ActionResult Search()
{
    var vm = new SearchViewModel();
    InitViewModel(vm);  

    //Simply call the second action with the initizalied ViewModel          
    return Search(vm);
}   

public ActionResult Search(SearchViewModel vm)
{       
    ...
    return View(vm);
}

但它不起作用,因为现在这两个动作之间存在歧义,asp.net 不知道该选择哪一个。

总之,我想找到一种方法来为 ViewModel 设置默认值,而不是在构造函数中设置它并覆盖用户选择。

换一种说法,我如何区分“空”视图模型和一些值从表单绑定的视图模型。

有什么想法吗?

【问题讨论】:

  • 为什么不能使用_currentUser
  • @markpsmith,_currentUser 是我的控制器的成员变量,它依赖于当前的 HttpContext。我可以在我的控制器中使用它,但我不能在 ViewModel 构造函数中使用它,因为我没有从那里访问 HttpContext 的干净方法。
  • 假设你使用的是 MVC5 和 C#5,你可以试试这个吗?公共组织类型?组织类型 {get;设置;} = null; //或者你想设置为默认值的任何值
  • @PratikGaikwad 问题是我无法轻松设置 OrganizationType 的默认值,我需要当前用户,然后我向我的数据库发出请求以检索当前的默认 OrganizationType用户(可以为空)。
  • OrganizationType 是枚举吗?如果您可以更改它,为什么不添加一个None 值,例如-1,它表示当用户未进行选择时提交的值。因此,第一次加载页面时,您实际上可以检查 OrganizationType 是否为空,然后默认它。否则,None 表示没有选择。

标签: asp.net asp.net-mvc


【解决方案1】:

好的,我想我找到了解决我自己问题的方法......

我可以使用控制器的 ModelState 属性来检查 ViewModel 是 empty 还是从表单绑定的:

public ActionResult Search(SearchViewModel vm = null)
{

    if (ModelState.Count == 0) 
    {        
        InitViewModel(vm);
    }       
    ...
    return View(vm);
}

因此,如果 ModelState.Count 等于 0,则表示用户没有更改任何过滤器。所以表单是空的,我们可以绑定我们的默认值。一旦用户更改其中一个过滤器或提交请求,ModelState.Count 将大于 0,因此我们不应设置默认值。否则我们会覆盖用户的选择。

【讨论】:

    【解决方案2】:

    你所做的事情的逻辑有点不确定。一般来说,如果一个值可以为空,那么 null 就是默认值。但是,您似乎试图在此处区分该值是否为 null (因为它未设置)或 null (因为用户将其显式设置为 null)。这种类型的语义差异通常是一个坏主意。如果 null 具有含义,则它应该始终具有该含义。否则,您的代码会变得更加混乱,因此通常会引入错误。

    也就是说,你不能指望ModelState 没有物品。老实说,在没有发布数据的情况下,我从来没有玩过ModelState,但可能存在一些没有发布数据但ModelState 可能有项目的情况。即使没有,这也是一个实现细节。如果 Microsoft 在以前没有项目的情况下进行更新,将项目添加到 ModelState 会怎样。然后,您的代码在没有明显原因的情况下中断。

    您在这里唯一可以真正依靠的是请求方法是 GET 还是 POST。在您的操作的 GET 版本中,您可以合理地假设用户没有进行任何修改。因此,在这种情况下,您可以简单地将值设置为您喜欢的任何值。

    在您的操作的 POST 版本中,用户进行了某种修改。但是,此时,无法再区分该值是否为 null 是因为它是 null 还是因为用户明确希望它是 null。因此,您必须按原样尊重价值。

    【讨论】:

    • 我同意区分“默认空值”和用户设置的空值并不是最好的主意。但我想让我的 ViewModel 初始化尽可能简单。为某些用户设置默认值是一种特殊情况,而不是一般性。我只关心 GET 请求,请求来自 HTML 表单,因此用户可能进行了修改。
    猜你喜欢
    • 2017-11-22
    • 1970-01-01
    • 2014-12-31
    • 2018-12-26
    • 2020-05-22
    • 1970-01-01
    • 2020-07-24
    • 1970-01-01
    • 2019-10-22
    相关资源
    最近更新 更多