ASP.NET MVC中模型实体的策略

时间:2012-10-09 13:49:43

标签: asp.net-mvc

我正在构建的Web应用程序的一部分是用户管理。因此,我需要一个用户实体。有几个涉及用户的用例,例如:

  • 显示用户列表
  • 显示单个用户
  • 修改用户联系信息
  • 编辑用户登录信息(用户名和密码)
  • 创建新用户

其中大多数都需要访问相同的属性,因此对所有情况使用相同的实体会很好。然后,如果我使用例如DisplayName属性,则所有地方都将使用相同的显示名称:

[Display(Name = "Username")]
public string Username { get; set; }

编辑用户时,我也想使用验证属性:

[Display(Name = "Username")]
[Required(ErrorMessage = "Username must be provided.")]
public string Username { get; set; }

当我有一个编辑某些属性的视图时,会出现问题,但不是全部。在“编辑用户联系信息”用例中,有些内容可用于编辑(例如,PhoneNumber),但有些内容不可用(例如,用户名)。但是,如果我使用相同的实体,则将验证具有验证属性的所有属性。

我在StackOverflow上找到了一些solutions to the validation problem,但我想知道在创建实体和视图模型时是否有任何“最佳实践”?

我更愿意尽可能地重复使用,以确保例如显示名称和验证在整个应用程序中是一致的。但通常会导致上述问题或复杂的继承权问题。

我应该:

  • 几个类似(但不完全相同)的实体?
  • 几个类似(但不完全相同)的视图模型?
  • 验证问题等问题的一个实体+解决方法?
  • ...

有什么建议吗?你自己如何做到这一点?

我应该注意,我经常显示的信息不仅仅是编辑的内容。例如,在编辑联系人信息时,我将获得某些属性的输入(例如,PhoneNumber和EmailAddress),但仍然向用户显示其他属性作为信息(例如,用户名)。

(如果重要,我正在使用ASP.NET MVC 3)

3 个答案:

答案 0 :(得分:1)

如果验证是您唯一的问题,我建议使用fluentvalidation(http://fluentvalidation.codeplex.com)。 这样您就可以根据情况设置验证规则(每个操作)。

我会为每个场景使用单独的视图模型,并在fluentmvc中使用RuleSets功能,这样我就不会违反DRY。

答案 1 :(得分:1)

我会考虑使用view model per view方法。虽然这似乎是额外的工作,但我相信它会使你的控制器和观点更简洁,更容易理解。非常清楚你在每种情况下的意图是什么,你仍然可以得到强有力的打字。

它还解决了mass assignment vulnerability潜在的另一个问题(与绑定包含/排除一样)。

最后使用这种技术不需要任何额外的编码位,有些人可能会认为是魔术,或者至少需要更仔细地阅读代码以了解此视图对模型的影响与其他视图相比,而不是其他视图因为所有三个使用相同的模型的方式略有不同。

答案 2 :(得分:0)

要向模型添加变量验证逻辑,可以实现IValidatableObject:

public class VariableValidationEntity : IValidatableObject
{
    public string UserName { get; set; }
    public bool ValidateMe { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (ValidateMe)
        {
            if (string.IsNullOrWhiteSpace(UserName))
            {
                yield return new ValidationResult("Username Required", new[] { "UserName" });
            }
        }
    }
}

然后,您可以根据您使用模型的环境指定验证逻辑。

或者,您可以为每个用例创建一个视图模型,甚至可以从基础模型派生经过验证的模型:

public class NonValidatedEntity
{
    public string UserName { get; set; }
}

public class ValidatedEntity : NonValidatedEntity, IValidatableObject
{
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (string.IsNullOrWhiteSpace(UserName))
        {
            yield return new ValidationResult("Username Required", new[] { "UserName" });
        }
    }
}

我认为后一种选择会更清晰。