2014-11-19 5 views
2

Я просто просматриваю некоторые учебники по интро для ASP.NET, и у меня есть достойное представление о том, как реализовать простое приложение администратора CRUD.Общие CRUD-контроллеры и представления

Существуют ли обычно используемые шаблоны для реализации общих действий «Список/Создать/Обновить/Удалить»? Кажется довольно утомительным, чтобы создавать строительные леса для каждой модели, а затем поддерживать все надстройки, редактировать и просматривать списки и контроллеры. Было бы намного более эффективным и менее подвержены ошибкам реализовать общие действия, как:

/List/Model 
/Edit/Model/id 
/Update/Model/id 
/Delete/Model/id 

, что бы справиться с любой модели.

+1

Этот пост SO имеет хорошее обсуждение того, что, как я думаю, вы пытаетесь сделать http://stackoverflow.com/questions/1124877/is-an-abstract-crud-controller-a-good-idea?rq=1 –

+0

Спасибо. Я думаю, что у разных людей разные варианты использования, и я знаю из прошлого опыта и решений, которые мы построили для других платформ, что общее решение работает хорошо для нас. – pixelmike

ответ

12

Я сделал нечто похожее, я думаю, на то, о чем вы говорите, в приложении администратора, которое я построил. В принципе, ключ заключается в использовании дженериков. Другими словами, вы создаете контроллер, как:

public abstract class AdminController<TEntity> : Controller 
    where TEntity : IEntity, class, new() 
{ 
    protected readonly ApplicationDbContext context; 

    public virtual ActionResult Index() 
    { 
     var entities = context.Set<TEntity>() 
     return View(entities); 
    } 

    public virtual ActionResult Create() 
    { 
     var entity = new TEntity(); 
     return View(entity); 
    } 

    [HttpPost] 
    public virtual ActionResult Create(TEntity entity) 
    { 
     if (ModelState.IsValid) 
     { 
      context.Set<TEntity>().Add(entity); 
      context.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 

     return View(entity); 
    } 

    ... 
} 

Другими словами, вы просто построить целую многоразовые структуру контроллера, с ключевыми элементами в том, что вы используете общий TEntity вместо конкретного класса. Обратите внимание, что TEntity определяется как IEntity, class, new(). Это делает несколько вещей. Во-первых, class позволяет рассматривать его как конкретный тип, а new() означает, что тип будет чем-то, что можно создать, а не нечто вроде абстрактного класса. IEntity - это просто местозаполнитель того, что вы можете использовать в своем приложении, чтобы все типы имели некоторый общий знаменатель. По крайней мере для приложения в стиле CRUD вам понадобится это, чтобы получить доступ к Id или аналогичному свойству для таких вещей, как действия редактирования и удаления. Говоря, что TEntity реализует IEntity, вы можете использовать любые свойства на IEntity. Если вы используете конкретный тип здесь вместо интерфейса, вы можете оставить часть class, например. where TEntity : Entity, new().

Затем, для того, чтобы использовать это, вы просто определить новый контроллер, который наследуется от AdminController<> и указать тип вы работаете с:

public class WidgetController : AdminController<Widget> 
{ 
    public WidgetController(ApplicationDbContext context) 
    { 
     this.context = context; 
    } 
} 

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

public WidgetController() 
{ 
    this.context = new ApplicationDbContext(); 
} 

Но я рекомендую вам изучить с помощью инъекции зависимостей, в целом. Кроме того, я использую контекст прямо здесь, чтобы упростить объяснение, но обычно вместо этого вы будете использовать сервисы, репозитории и т. Д.

Наконец, если вы обнаружите, что вам нужно настроить определенные части действия CRUD, но не обязательно все это, вы всегда можете добавлять методы в качестве точек расширения. Например, предположим, что вам необходимо заполнить список выбора для одного конкретного объекта, вы можете сделать что-то вроде:

public abstract class AdminController<TEntity> : Controller 
    where TEntity : IEntity, class, new() 
{ 
    ... 

    public virtual ActionResult Create() 
    { 
     var entity = new TEntity(); 
     BeforeReturnView(); 
     return View(entity); 
    } 

    ... 

    protected virtual void BeforeReturnView() 
    { 
    } 

    ... 

И потом:

public class WidgetController : AdminController<Widget> 
{ 
    ... 

    protected override void BeforeReturnView() 
    { 
     ViewBag.MySelectList = new List<SelectListItem> 
     { 
      ... 
     }; 
    } 
} 

Другими словами, у вас есть крюк в вашей базовый метод действий, который вы переопределите, чтобы просто изменить этот конкретный бит функциональности вместо того, чтобы переопределить все действие.

Вы также можете принять это дальше, чтобы включить такие вещи, как просмотреть модели, где вы могли бы расширить свое родовое определение класса к чему-то вроде:

public abstract class AdminController<TEntity, TEntityViewModel, TEntityCreateViewModel, TEntityUpdateViewModel> 
    where TEntity : IEntity, class, new() 
    where TEntityViewModel : class, new() 
    ... 

И потом:

public class WidgetController : AdminController<Widget, WidgetViewModel, WidgetCreateViewModel, WidgetUpdateViewModel> 
{ 
    ... 
} 

Все зависит от что нужно вашему приложению.

+0

Спасибо, это очень полезно. – pixelmike

+0

thx Chris, хорошее расширение нескольких других сообщений, я буду держать это под рукой :-) –

+0

@ Крис, я должен вам много пива за то время, когда вы спасли меня своими замечательными ответами, и это не исключение. Ta. –

Смежные вопросы