Подмостки MVC дублируют мои поля модели

Кажется, у меня запуталась странная проблема, и после нескольких часов царапин на голове я, кажется, сузил проблему до комбинации частичных классов и виртуальные свойства. Когда я переопределяю свойство, которое в частичном классе, сидя в отдельном файле, MVC дублирует поля в моем представлении. Я использую Visual Studio 2013, и проблему можно дублировать, выполнив следующие шаги:

  • Откройте Visual Studio и создайте новый проект. Выберите "Веб" под категориями, затем выберите "Веб-приложение ASP.NET". Я нацелен на .NET 4.5.
  • Выберите "Пусто" из выбора шаблона, затем установите флажок MVC, чтобы он добавлял основные папки и ссылки.
  • Как только проект будет создан, щелкните правой кнопкой мыши по папке Models и создайте новый класс под названием MyModel.cs.

Добавьте эти строки в новый файл:

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.

Добавьте эти строки в файл:

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 и для раскрывающегося списка Модель-класс выберите MyModel.

Как только MVC создаст шаблон, вы увидите, что он добавляет First Name и Last Name дважды. Проблема, похоже, связана с частичными классами, потому что, если я перемещаю содержимое MyModelCustom.cs в MyModel.cs, все работает нормально. Однако это не просто частичные классы. Если я создаю новое свойство (по сравнению с перегрузкой) в частичном классе, он не дублирует это свойство. Таким образом, это, кажется, комбинация частичных классов и переопределение виртуальных свойств.

Может кто-нибудь, пожалуйста, подтвердите, является ли это ошибкой или если я что-то делаю неправильно?

Ответ 1

Взгляните на источник CodePlex для MvcScaffolding EnvDTETypeLocator.cs

    /// <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 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 (дизайн Time Reflection).

2) Если класс, отлитый как CodeClass2, имеет членов, класс добавляется в representatives

3) Когда оценивается частичный класс, каждый файл будет посещаться в определенном контексте (часто приводя к консолидации элементов, которые должны быть переопределены)


Интересное различие между отражением времени выполнения и отражением времени проектирования: sic

Элемент управления ASP.NET имеет два различных набора функций, когда он выполняется во время выполнения внутри страницы или используется во время разработки внутри конструктора хоста. Временные возможности определяют на основе конфигурации разметку, которая выводится элементом управления. Вместо этого возможности дизайна-времени могут быть полезны визуальному дизайнеру, например Microsoft Visual Studio 2005. Возможности времени разработки позволяют автору страницы настраивать элемент управления для времени выполнения в декларативном и WYSIWYG (что-вы-видите-есть-что вы-получите).

Вывод:

MVC Scaffolding использует отражение, но это гораздо менее надежное отражение времени дизайна.

Время отражения дизайна не совпадает с отражением времени выполнения. Полностью скомпилированный класс является конечным результатом разрешения наследования и частичным объединением и приоритетом. Design Time Reflection дает наилучшие предположения о том, как работать со сложными, многочастными типами.

Если вы хотите полагаться на строительные леса, лучше не нажимать на него. Когда вы получаете такие ошибки, попробуйте упростить ViewModels:

  • Попробуйте консолидировать свои частичные классы
  • Попробуйте удалить тезисы/виртуальные страницы.

Ответ 2

Немного обоим. Ошибка или нет, если MVC неправильно работает, вам придется либо постоянно бороться с каркасом, либо изменять свой подход к проблеме.

Как правило, я обнаружил, что, когда вам нужно бороться с инфраструктурой MVC, чтобы заставить ее вести себя так, как вы хотите, гораздо легче изменить свой подход к проблеме. В противном случае вы в конечном итоге будете сражаться с этим конкретным сражением, пока вы в конце концов не подчинитесь. Возьмите его у кого-то, кто усвоил этот урок.

С учетом более простых подходов, вот несколько вещей, которые вы могли бы попробовать:

  • Если вы переписываете много свойств, создайте отдельные классы с общими именами свойств (FirstName, LastName). Затем используйте Лучший способ клонирования свойств разрозненных объектов для сортировки данных между объектами.

  • Вы также можете использовать Fody PropertyChange прослушиватели для обработки любой логики, когда эти значения изменены, тем самым устраняя необходимость частичное переопределение полностью.

  • Конечным вариантом будет переопределить шаблоны лесов, чтобы пропустить переопределенные свойства. Не знаете, как бы вы это заметили.