Контроллер подкласса с моделью подкласса - PullRequest
1 голос
/ 08 июля 2011

Я работаю над проектом ASP.Net MVC 3, где многим действительно простым сущностям просто необходима базовая поддержка CRUD из административного интерфейса. Все эти сущности имеют простой доменный объект с Id, Name, и для этой цели существует абстрактный базовый класс NamedEntity.

У меня есть базовый контроллер, NamedEntityController<T> where T : NamedEntity, который может обрабатывать простые операции crud со всеми его методами виртуальными. Есть хороший маленький NamedEntityCreateOrUpdateModel<T>, который используется для передачи данных назад и вперед в представления.

Теперь у меня есть определенный подкласс NamedEntity, называемый Topic, который имеет дополнительные свойства и, в частности, имеет отношения Родитель / Дочерний с другими темами, поэтому нам нужно захватить целочисленный идентификатор Родителя, который значение для других NamedEntity операций. Для этого я подклассифицировал до TopicsController: NamedEntityController<Topic> и TopicCreateOrUpdateModel : NamedEntityCreateOrUpdateModel<Topic>

(Прежде чем кто-то откусит мне голову, вся настоящая работа выполняется в слое Tasks, я просто упрощаю описание проблемы здесь.)

Базовый контроллер определяет

[HttpPost]
public virtual ActionResult Edit(NamedEntityCreateOrEditModel<T> Model)
    { ... }

Подкласс определяет

[HttpPost]
public override ActionResult Edit(NamedEntityCreateOrEditModel<Topic> Model)
{
TopicCreateOrEditModel tm = Model as TopicCreateOrEditModel;
...
}

(для краткости не показано: версия «Get» для каждого Edit корректно устанавливает базовый NamedEntityCreateOrEditModel или специфичный для темы подкласс такого типа и возвращает View() для этой модели.)

Я ясно вижу из отладочных точек останова, что вызывается метод Edit (post) подкласса. Но приведенный выше актерский состав всегда приводит к null, что побеждает точку подкласса.

Если я попытаюсь создать

[HttpPost]
public override ActionResult Edit(TopicCreateOrEditModel Model) { ... }

MVC жалуется, что действие этого нового метода и метода базового класса неоднозначно.

Есть ли простое решение этой проблемы? В этом случае я мог бы полностью обойти контроллер / модель базового класса и сказать: «если вам нужны дополнительные поля помимо простых, не наследуйте», но это кажется очень неправильным, особенно с учетом того, что доменные объекты наследуются.

Ответы [ 3 ]

1 голос
/ 25 октября 2013

Явно используя TryUpdateModel в действии, вы можете удалить параметр и сделать подпись такой же. Это позволяет использовать ключевое слово override, например:

public class A { }
public class B : A { }

public class AController {

    [HttpPost]
    public virtual ActionResult Edit() {
        A a = new A();
        TryUpdateModel<A>(a);

        if (ModelState.IsValid)
            a.save();
    }
}

public class BController : AController {

    [HttpPost]
    public override ActionResult Edit() {
        B b = new B();
        TryUpdateModel<B>(b);

        if (ModelState.IsValid)
            b.save();
    }
}

Это исправило AmbiguousMethodException для меня, и вызовы к обоим Edit действиям перенаправлены правильно. Однако могут возникнуть проблемы с безопасностью, о которых я не знаю.

0 голосов
/ 08 июля 2011

Очевидно, что MVC передает экземпляр NamedEntityCreateOrEditModel<Topic> вместо TopicCreateOrEditModel.Так как в этом случае я не вижу значения полиморфизма для Edit, я полагаю, явно пометить его как new должно быть хорошо (да, это взлом).

[HttpPost]
public new ActionResult Edit(TopicCreateOrEditModel Model) { ... }

Более ортодоксальныйПодход, вероятно, заключается в написании пользовательского связывателя модели для типа NamedEntityCreateOrEditModel<Topic> для создания экземпляра TopicCreateOrEditModel, если текущий контроллер TopicsController.

Или, ничего не зная о вашем текущем использовании наследования, просто удалитеEdit (и аналогичные методы CRUD) в NamedEntityController<T>, поскольку я не вижу его значения.Если у вас есть веская причина для его существования, игнорируйте это предложение.

0 голосов
/ 08 июля 2011

Когда вызывается Edit вашего подкласса, передается ли он NamedEntityCreateOrEditModel<Topic> или TopicCreateOrEditModel? Первый проваливает приведение (само собой разумеется, что вы можете привести производный класс к его базе, но не наоборот).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...