【问题标题】:ASP.NET MVC Bad Practices: Optional Submodel With Required PropertyASP.NET MVC 不良做法:具有必需属性的可选子模型
【发布时间】:2016-11-30 15:10:12
【问题描述】:

Google 上有大量资源,但我无法完全理解在我的场景中需要做什么:

我有这门课:

public class CompanyLanguage : EntityBase
{
    public int CompanyId { get; set; }
    public int LanguageId { get; set; }
    public bool IsDefault { get; set; }


    public virtual Company Company { get; set; }
    public virtual Language Language { get; set; }
}

Language 定义为:

public class Language:EntityBase
{
    [Required]
    [DisplayName("Language Code")]
    public string LanguageCode { get; set; }

    [Required]
    [MaxLength(2, ErrorMessage ="2 characters maximum")]
    [DisplayName("2 Char Language Code")]
    public string LanguageCode2Char { get; set; }

    [Required]
    [DisplayName("Language Name")]
    public string LanguageName { get; set; }

    public virtual List<LabelLanguage> LabelLanguages { get; set; }
}

运行Fortify Scan 会将以下问题作为高优先级返回:

(ASP.NET MVC 不良做法:具有必需属性的可选子模型)

我们无法运行强化扫描 - 它正在由其他人运行,因此我需要正确进行更改,以免它直接返回。

我查看过的所有资源都表明可以进行低发攻击 - 即空 Language,即使 Language 具有一些必需的属性。

对我来说,这是一个有效的场景——Language 的必需属性仅在 Language 不为空时才需要。

那么我应该怎么做才能解决这个问题?我是需要public int LanguageId { get; set; },还是public virtual Language Language { get; set; },还是两者都需要?

或者我完全错了,我必须做其他事情?正如我所说,我无法测试这些,因为必须将软件发送出去进行测试,否则我会尝试各种方式。

【问题讨论】:

  • 所以你是直接发送这个 ef 实体到一个没有视图模型的视图?
  • 我 - 我已经读到我真的应该使用视图模型,但我的视图模型实际上与实体完全相同,这似乎我正在添加更多代码和维护奖励不多。你怎么看?
  • 嗯,奖励是关注点分离和更简洁的代码。由于您正在向视图发送多对多连接实体,因此您可能不需要所有这些信息。很高兴看到视图和控制器操作以了解您在做什么,但我猜测您有公司和语言的下拉菜单。如果是这种情况,唯一需要返回视图的是每个下拉列表的 Id 列表和描述,而不是完整的 ef 实体。
  • 是的,我相信视图模型是最好的方法,因为它们对视图中的信息进行建模。该视图只要求某人选择一种语言和/或公司。他们不是在创建一家验证 ef 模型的公司。是的,这需要重构成本。然后,您可以在控制器操作中将视图模型和 ef 模型结合起来,甚至可以使用 linq 查询直接投影到视图模型中。在将它们发送到视图之前。

标签: c# asp.net asp.net-mvc


【解决方案1】:

总结我们从 cmets 的讨论。

  1. 创建一个仅对满足相应视图所需的信息进行建模的视图模型。
  2. 从域 ef 模型中填充控制器操作中的视图模型
  3. 使用 linq 查询或 Automapper 直接将项目投影到视图模型中。

您的问题的示例视图模型

public class CompanyLanguageEditViewModel
{
    [DisplayName("Company")]
    [Required]
    public int CompanyId { get; set; }

    [DisplayName("Language")]
    [Required]
    public int LanguageId { get; set; }
    public bool IsDefault { get; set; }

    public IEnumerable<SelectListItem> Companies{ get; set; }
    public IEnumerable<SelectListItem> Languages { get; set; }
}

在你看来,你可以使用

@Html.DropDownListFor(x => x.CompanyId, Model.Companies);

您的标签将是 Country 并且您只会回复您需要的内容

【讨论】:

  • 绝对是我应该走的路!作为快速解决方法,要解决此问题,是否将 public virtual Language Language { get; set; } 设为必需的属性?那有效吗?正如我所说,我无法尝试并查看,因为我没有进行测试。时间很短,进行所有这些 ViewModel 更改将意味着无法赶上最后期限。
  • 这如何帮助您解决最初的问题?您仍在将 ef 模型传递给您的视图。虚拟也是不必要的。那个 virtual 是这样 ef 可以返回一个代理对象以进行延迟加载。而且我相当确定,如果您将 Language 标记为必需,则在您发布时将需要 Language 的所有属性
  • 原来的问题是子模型(Language)具有必需的属性,即使Language在CompanyLanguage中是可选的。所以我会假设需要语言,会解决问题吗?
  • 所以如果需要这些语言属性,您是否将所有语言属性都放在隐藏字段中并将它们也发布回来?模型绑定器不会仍然抛出验证错误,因为您实际上并没有发回 LanguageCode 或 LanguageCode2Char 吗?
  • 谢谢,重构已经完成了一半——这是一个更好的解决方案。
猜你喜欢
  • 1970-01-01
  • 2013-12-27
  • 2021-07-02
  • 1970-01-01
  • 2017-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-02
相关资源
最近更新 更多