MVC脚手架正在复制我的模型字段

时间:2015-05-19 23:17:55

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

我似乎遇到了一个奇怪的问题,经过数小时的搔痒,我似乎已将问题缩小到partial classesvirtual properties的组合。当我覆盖部分类中的属性,坐在单独的文件中时,MVC会复制我视图中的字段。我正在使用Visual Studio 2013,可以通过以下步骤复制该问题:

  1. 打开Visual Studio并创建一个新项目。在类别下选择Web,然后选择" ASP.NET Web Application"。我的目标是.NET 4.5。
  2. 选择"清空"从模板选择中,然后检查MVC复选框,以便添加核心文件夹和引用。
  3. 创建项目后,右键单击Models文件夹并创建一个名为MyModel.cs的新类。
  4. 将这些行添加到新文件中:

    public abstract partial class MyOriginalModel
    {
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
    }
    
    public partial class MyModel : MyOriginalModel
    {
    
    }
    
    1. 现在再次右键单击Models文件夹并创建另一个名为MyModelCustom.cs的新类。
    2. 将这些行添加到文件中:

      public partial class MyModel
      {
          [System.ComponentModel.DisplayName("First Name")]
          [System.ComponentModel.DataAnnotations.Required]
          public override string FirstName
          {
              get
              {
                  return base.FirstName;
              }
              set
              {
                  base.FirstName = value;
              }
          }
      
          [System.ComponentModel.DisplayName("Last Name")]
          [System.ComponentModel.DataAnnotations.Required]
          public override string LastName
          {
              get
              {
                  return base.LastName;
              }
              set
              {
                  base.LastName = value;
              }
          }
      }
      
      1. 现在构建项目,然后右键单击Controllers文件夹并添加一个新控制器。选择"带有读/写操作的MVC 5控制器"并称之为NamesController。右键单击Create方法,然后转到" Add View"。在模板下拉列表中,选择Create,然后在“模型类”下拉列表中选择MyModel
      2. MVC创建模板后,您会看到它会两次添加First NameLast Name。该问题似乎与部分类有关,因为如果我将MyModelCustom.cs的内容移动到MyModel.cs,一切正常。但是,它不仅仅是部分类。如果我在分部类中创建一个新属性(而不是重载一个),则它不会复制该属性。所以它似乎是部分类和重写虚拟属性的组合。

        有人可以确认这是一个错误还是我做错了什么?

2 个答案:

答案 0 :(得分:3)

这两者都有。是否存在错误,如果MVC脚手架不正确,您将不得不经常对抗框架或改变您对问题的处理方法。

作为一般规则,我发现当你必须对抗MVC框架以使其按照你想要的方式运行时,那么改变你对问题的处理方法要容易得多。否则,你将最终反复战斗,直到你最终遵守。从那些以艰难的方式吸取教训的人那里拿走它。

考虑到更简单的方法,您可以尝试以下几种方法:

  1. 如果要覆盖很多属性,请使用属性的常用名称(FirstName,LastName)创建单独的类。然后使用Best way to clone properties of disparate objects编组对象之间的数据。

  2. 您还可以使用Fody PropertyChange侦听器来处理这些值更改时所需的逻辑,从而完全不需要部分覆盖。

  3. 最后一个选项是override the scaffolding templates跳过被覆盖的属性。不知道你怎么会发现它。

答案 1 :(得分:2)

查看MvcScaffolding的EnvDTETypeLocator.cs

的CodePlex来源
    /// <summary>
    /// Out of a set of CodeType instances, some of them may be different partials of the same class.
    /// This method filters down such a set so that you get only one partial per class.
    /// </summary>
    private static List<CodeType> PickArbitraryRepresentativeOfPartialClasses(IEnumerable<CodeType> codeTypes)
    {
        var representatives = new List<CodeType>();
        foreach (var codeType in codeTypes) {
            var codeClass2 = codeType as CodeClass2;
            if (codeClass2 != null) {
                var matchesExistingRepresentative = (from candidate in representatives.OfType<CodeClass2>()
                                                     let candidatePartials = candidate.PartialClasses.OfType<CodeClass2>()
                                                     where candidatePartials.Contains(codeClass2)
                                                     select candidate).Any();
                if (!matchesExistingRepresentative)
                    representatives.Add(codeType);
            } else {
                // Can't have partials because it's not a CodeClass2, so it can't clash with others
                representatives.Add(codeType);
            }
        }
        return representatives;
    }
}

1) PickArbitraryRepresentativeOfPartialClasses,该方法使用Linq any()确认codeType as CodeClass2有成员。

CodeClass2 EnvDTE 的部分类类型,Visual Studio的核心自动化库负责IDE代码生成(设计)时间反思)。

2)如果投放为CodeClass2的类确实有成员,则该类会添加到representatives

3)评估部分类时,将在不同的上下文中访问每个文件(通常会导致应该覆盖的元素的合并)

运行时反射和设计时反思之间的一个有趣区别: sic

  

ASP.NET控件具有两组不同的功能,用于在页面内的运行时执行或在主机设计器内的设计时使用。运行时功能根据配置确定控件输出的标记。相反,设计时功能受益于可视化设计器,例如Microsoft Visual Studio 2005.设计时功能让页面作者在声明和WYSIWYG中配置运行时控件(你看到的是什么) - 你得到的方式。

<强>结论:

MVC Scaffolding确实使用了反射,但它的设计时间反射却不那么可靠。

设计时间反射与运行时反射不同。完全编译的类是继承解析和部分组合和优先级解析的最终结果。设计时间反射可以最好地猜测如何使用复杂的多部件类型。

如果你想依靠脚手架,最好不要限制它。当你遇到这样的错误时,请尝试简化你的ViewModel:

  • 尝试合并您的部分课程
  • 尝试删除您的摘要/虚拟