C# MVC的格式化逻辑属于哪里?

C# MVC的格式化逻辑属于哪里?,c#,asp.net-mvc,asp.net-mvc-3,language-agnostic,C#,Asp.net Mvc,Asp.net Mvc 3,Language Agnostic,假设我的电话号码以10位字符串的形式存储在数据库中: 0000000000 我想在将此电话号码呈现给用户时将其格式化为: (000)000-0000 我在一个实用程序程序集中有一个扩展方法来处理这种格式: static string ToPhoneNumber(this string value) { return Regex.Replace(value, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3"); } 我的问题是,我在什么时候应用这种转换? 1)

假设我的电话号码以10位字符串的形式存储在数据库中:

0000000000

我想在将此电话号码呈现给用户时将其格式化为:

(000)000-0000

我在一个实用程序程序集中有一个扩展方法来处理这种格式:

static string ToPhoneNumber(this string value)
{
    return Regex.Replace(value, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");
}
我的问题是,我在什么时候应用这种转换?

1) 他认为:

@Model.PhoneNumber.ToPhoneNumber()
2) 在视图模型中:

public string FormattedPhoneNumber
{
    get
    {
        return this.PhoneNumber.ToPhoneNumber()
    }
}
3) 在控制器中:

userModel.FormattedPhoneNumber = userModel.PhoneNumber.ToPhoneNumber()
4) 在域模型中(与#2相同的实现)

5) 在服务中(与#3相同的实现)

此外,答案是否取决于是否需要全局格式化(如电话号码)而不是单个视图上的单独一次性格式化


我会给出我的想法,但不想影响任何答案。

我认为视图有责任决定如何显示数据。因为只有视图知道哪些内容可用于表示。另一方面,在控制器中执行此操作可能更容易。控制器将知道用户的语言环境。总的来说,我认为这没什么区别。

选项1是最好的,其次是2。
在控制器中,您实际上应该删除格式以将其发送到服务层,因此域模型和服务模型都不知道格式。

我个人喜欢将内容保留在我的ViewModel中,因为如果不这样做,您的视图中会出现奇怪的代码。让我们以你为例

Razor视图:

@using MyNamespace.Models.Extensions
@model MyNamespace.Models.ViewModels.IndexViewModel

@if (string.IsNullOrWhiteSpace(Model.PhoneNumber) {
   <div> @Model.PhoneNumber.ToPhoneNumber() </div>  
}
@model MyNamespace.Models.ViewModels.IndexViewModel

@Model.FormattedPhoneNumber
视图模型:

 public string FormattedPhoneNumber {
     get {
         return PhoneNumber.IsEmpty()
         ? "Not Available"
         : PhoneNumber.ToPhoneNumber();
     }
 }
您当然可以改进我的代码,但关键是它使您的视图更简单,并且避免分支逻辑造成混乱


而且,我从来没有声称自己是圣人,所以我并不总是听从自己的建议,但我应该这样做。照我说的去做,而不是照我做的去做:)

这取决于你对ViewModel的定义,你是否遵循一种(自创的)MVCVM*方法,除了你的域模型之外,你还有一个特定于你的视图的ViewModel

如果是这样的话,VM肯定会包含格式化逻辑,这就是首先使用这个视图模型对视图建模的全部意义。因此,选择2

这就是说,其背后的原因是,如果您是这样格式化的,那么您自己的格式化将开始遵循干燥原则:

@Regex.Replace(Model.PhoneNumber, @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");
因为您有一个扩展方法,所以在您的视图中调用格式化程序根本不是什么大问题,但我还是更喜欢在专用VM中进行

如果您的虚拟机实际上只是包含原始数据的域模型(请参阅模式1),那么它肯定会出现在您的视图中,所以选择1。需要注意的是,如果您使用这种模式,我建议您不要使用它,因为它使您的视图与低级对象强耦合,您最好将其抽象为您需要的内容,以确保域模型+视图模型之间的耦合实际上是强耦合的(即,在编译时编译,而不是在运行时!)

最重要的是,这肯定不会进入你的领域模型


*模型、视图、控制器、视图模型。其中ViewModel包含要在视图中使用的数据,数据的格式是它所要求的。

我将把它放在ViewModel中,而不是视图中。该视图旨在向最终用户展示数据/信息。保持关注点的分离确保每个对象尽可能独立。如果将格式化的数字传递给视图,则视图不关心要显示的内容,只显示格式化的数字。

首先,对于一般的体系结构模式,尤其是那些处理“关注点分离”的模式,最终裁决者始终是“我的场景中的最佳方法是什么”-我坚信,教条式地遵守一套规则而不考虑自己的计划和需要是一种可怕的做法。更不用说,这里没有明确的共识:根据你的XYZ(MVC、MVP、MVVM)的不同,你会发现对互联网上的内容有相反的看法

也就是说,我对这个问题的快速回答是“运用你的判断”

“在视图中”的参数:

  • 它处理演示,因此是视图的责任
“在视图模型中”的参数:

  • 通常,视图模型的作用是提供模型的“准备好数据绑定”表示—因此,将模型数据转换为视图可直接使用的形式是视图模型的责任
模型的参数:

  • 这可能是模型数据过于常见的表示形式;因此,在DRY之后,模型将承担此表示的责任
控制器的参数:

userModel.FormattedPhoneNumber = userModel.PhoneNumber.ToPhoneNumber()
  • 。。。好吧,我想不出一个合理的。控制器通常会对动作做出响应,因此要证明它属于这里是一种延伸
我想指出的一点是,只要系统中的一个点接受并承担责任,并且责任完全由该组件/层/类来处理,您就完成了主要目标,即防止稀释/重复/低内聚性

我个人的观点,fwiw,可能会落在视图或视图模型上。如果这是WPF,我几乎可以肯定地说是视图(通过WPF数据绑定可用的格式提供程序)。在web世界中,我可能倾向于视图,尽管该模型存在一个强有力的论据——假设您现在希望通过REST/JSON/etc服务公开此数据:您可以轻松处理此更改(假设您希望返回格式化数据,即)


TL/DR:这要视情况而定;遵循常识,运用你的判断。把所有相关的逻辑放在一个地方是很重要的,并质疑任何教条/诫命式的“你应该”陈述

我认为这是建模,而不是形式