ViewModel

时间:2016-10-18 13:52:50

标签: asp.net asp.net-mvc

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

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

我的(简化)ViewModel:

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 值对应于空过滤器,并且它是用户可以做出的选择。所以我无法覆盖它。

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

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

    return View(vm);
}

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

我还尝试过两个Action,一个没有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设置默认值,而无需在构造函数中设置它并覆盖用户选择。

另一种说法是,如何区分“空”ViewModel与某些值从表单绑定的ViewModel。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

好的我觉得我找到了解决自己问题的方法......

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

public ActionResult Search(SearchViewModel vm = null)
{

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

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

答案 1 :(得分:0)

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

尽管如此,你不能指望ModelState没有物品。老实说,在没有发布数据的情况下,ModelState从未玩过ModelState,但在某些情况下可能没有帖子数据但ModelState可能有项目。即使没有,这也是一个实现细节。如果Microsoft在以前没有项目的情况下执行将项目添加到import pandas as pd %matplotlib inline df =pd.read_csv(‘C:/Users/caol3/Downloads/Data Sampler.csv’) IOErrorTraceback (most recent call last) <ipython-input-3-3740a47c4f96> in <module>() ----> 1 df =pd.read_csv('C:/Users/caol3/Downloads/Data Sampler.csv') /opt/conda/envs/python2/lib/python2.7/site-packages/pandas/io/parsers.pyc in parser_f(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, escapechar, comment, encoding, dialect, tupleize_cols, error_bad_lines, warn_bad_lines, skip_footer, doublequote, delim_whitespace, as_recarray, compact_ints, use_unsigned, low_memory, buffer_lines, memory_map, float_precision) 560 skip_blank_lines=skip_blank_lines) 561 --> 562 return _read(filepath_or_buffer, kwds) 563 564 parser_f.__name__ = name /opt/conda/envs/python2/lib/python2.7/site-packages/pandas/io/parsers.pyc in _read(filepath_or_buffer, kwds) 313 314 # Create the parser. --> 315 parser = TextFileReader(filepath_or_buffer, **kwds) 316 317 if (nrows is not None) and (chunksize is not None): /opt/conda/envs/python2/lib/python2.7/site-packages/pandas/io/parsers.pyc in __init__(self, f, engine, **kwds) 643 self.options['has_index_names'] = kwds['has_index_names'] 644 --> 645 self._make_engine(self.engine) 646 647 def close(self): /opt/conda/envs/python2/lib/python2.7/site-packages/pandas/io/parsers.pyc in _make_engine(self, engine) 797 def _make_engine(self, engine='c'): 798 if engine == 'c': --> 799 self._engine = CParserWrapper(self.f, **self.options) 800 else: 801 if engine == 'python': /opt/conda/envs/python2/lib/python2.7/site-packages/pandas/io/parsers.pyc in __init__(self, src, **kwds) 1211 kwds['allow_leading_cols'] = self.index_col is not False 1212 -> 1213 self._reader = _parser.TextReader(src, **kwds) 1214 1215 # XXX pandas/parser.pyx in pandas.parser.TextReader.__cinit__ (pandas/parser.c:3427)() pandas/parser.pyx in pandas.parser.TextReader._setup_parser_source (pandas/parser.c:6861)() IOError: File C:/Users/caol3/Downloads/Data Sampler.csv does not exist 的更新,该怎么办?然后,你的代码中断没有明显的原因。

您唯一可以依赖的是请求方法是GET还是POST。在您的操作的GET版本中,您可以合理地假设用户未进行任何修改。因此,在这种情况下,您可以毫无顾虑地将值设置为您喜欢的任何值。

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