ASP.NET MVC:我的视图应该有多蠢?

4

好的,我不是在谈论商业逻辑决策,而是UI决策。

例如,我正在呈现一个表格,其中一列显示需要进行格式化的DateTime?属性。由于该值可为空,因此需要在格式化之前检查它是否为空。

如果我想要严谨一些,我会在我的ViewModel上有一个FormattedDate属性:

public class MyViewModel 
{
    ...
    public DateTime? Date { get; set; }

    public string FormattedDate 
    {
        get 
        {
            return this.Date.HasValue ? this.Date.Value.ToShortDateString() : "";
        }
    }
}

<%= Html.Encode(Model.FormattedDate) %>

或者我可以节省几行代码,直接将其放入视图中:
<%= Html.Encode(Model.Date.HasValue ? Model.Date.Value.ToShortDateString() : "")%> 

在这种情况下,由于这只影响视图,我认为第二种方式是可以的(而且更紧凑),但是我该在哪里划线,以避免我的视图被服务器端代码淹没,又不让我的ViewModel被“格式化”属性淹没?
2个回答

4

如果您直接将代码放在View中,它并不会真正为您节省任何相关代码行 - 它只是将其移动到了别的地方。

然而,如果您将其放在View中,那么您只能在那里使用它。您无法在其他地方重用ViewModel的逻辑,也无法对其进行单元测试。

保持您的Views非常简单。我认为Views的圈复杂度应该尽可能低。

有关更多详细信息,请参见此答案


这就解决了视图是否应该有任何逻辑的问题 - 不应该有。至于逻辑应该放在哪里,我倾向于使用David M建议的格式化扩展方法 - 这使得逻辑易于测试,并将其与特定的ViewModel解耦(当然,我完全可以看到其他场景,其中它更具有领域对象特定性而不是格式化日期,因此必须放在ViewModel本身中)。 - Veli Gebrev
1
虽然扩展方法可能是可测试的,但视图不是,这意味着您将没有单元测试来验证它是否从视图中正确调用。我认为通过在扩展方法中实现一些视图和在ViewModel中实现一些视图,您将违反内聚性原则。将所有内容放入ViewModel中将为您提供更高的内聚性,同时遵循单一职责原则。 - Mark Seemann

1
如果这是你经常做的事情,也许你可以为Nullable<DateTime>编写一个扩展方法,像这样:
static public string Format(this DateTime? value)
{
    return value.HasValue ? value.ToShortDateString() : string.Empty;
}

避免ViewModel或View的混乱。


是的,那是一个不错的选择,在我的情况下有点过头了,但将来会记住它 :) - Veli Gebrev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接