Другой вариант заключается в использовании RegisterInitializer метод:
container.RegisterInitializer<BaseControllerType>(controller =>
{
controller.UnitOfWork = container.GetInstance<IUnitOfWork>();
}
Он сохраняет все конфигурации в корневой состав и не загрязняет окружающую среду ваша база кода со всеми атрибутами.
Update: (как обещали)
Хотя это прямой ответ на ваш вопрос, я должен предоставить вам лучший вариант, так как использование базового класса для этого является IMO не правильный дизайн по нескольким причинам.
- Абстрактные классы могут стать реальными классами пита, поскольку они имеют тенденцию расти к классу бога, который имеет все виды перекрестных проблем режущими
- Абстрактный класс, особенно при использовании инъекций собственности, скрывает необходимые зависимости.
С акцентом на пункте 2. Если вы хотите модульное тестирование контроллера, который наследуется от базового контроллера, вы не имеете никакого способа знать, что этот контроллер зависит от IUnitOfWork
. Это можно решить с помощью инъекции конструкторы вместо инъекции собственности:
protected abstract class BaseController : Controller
{
protected readonly IUnitOfWork uoW;
protected BaseController (IUnitOfWork uoW)
{
this.uoW = uoW;
}
}
public class SomeController : BaseController
{
public SomeController(IUnitOfWork uoW) : base(uoW) { }
}
В то время как это решает пункт 2, пункт 1 по-прежнему скрывается. Основная причина, по которой вы хотите, как вы говорите, состоит в том, что вы не хотите фиксировать свои изменения в каждом методе Action
. Изменения должны быть сохранены контекстом, когда запрос будет выполнен.И думать о дизайне таким образом - это хорошо, потому что сохранение изменений есть или может рассматриваться как cross cutting concern, а способ реализации этого более или менее известен как AOP.
Если дело доходит до AOP, особенно если вы работаете с атомарными действиями в методах действий ваших контроллеров, есть намного лучше, больше SOLID и более гибкий дизайн, который имеет дело с этим очень красиво.
Я имею в виду шаблон Command/Handler, который подробно описан here (также читается this for the query part of your application).
С помощью этих шаблонов вы не вводите общую абстракцию, а вводите необходимые абстракции ICommandHandler<TCommand>
.
Методы действий уволили бы ответственного манипулятора за это конкретное действие. Все CommandHandlers могут просто быть оформлены одним открытым родового SaveChangesCommandHandlerDecorator
, «ValidationDecorator», «CheckPermissionsDecorator», и т.д. ...
Быстрый пример:
public class MoveCustomerCommand
{
public int CustomerId;
public Address NewAddress;
}
public class MoveCustomerCommandHandler : ICommandHandler<MoveCustomerCommand>
{
public void Handle(MoveCustomerCommand command)
{
// retrieve customer from database
// change address
}
}
public class SaveChangesCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
{
private readonly ICommandHandler<TCommand> decoratee;
private readonly DbContext db;
public SaveChangesCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee, DbContext db)
{
this.decoratee = decoratee;
this.db = db;
}
public void Handle(TCommand command)
{
this.decoratee.Handle(command);
this.db.SaveChanges();
}
}
// Register as
container.Register(typeof(ICommandHandler<>), new []{Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(SaveChangesCommandHandlerDecorator<>));
// And use in controller as
public ActionResult MoveCustomer(int customerId, Address address)
{
var command = new MoveCustomerCommand
{ CustomerId = customerId, Address = address };
this.commandHandler.Handle(command);
return View(new ResultModel());
}
Это держит ваши контроллеры чистые и пусть это делают что он должен делать, а именно быть слоем между бизнес-логикой (реализация командщика в этом случае) и представлением.
это [в документах] (http://simpleinjector.readthedocs.org/en/latest/extensibility.html#overriding-property-injection-behavior) – qujck
Почему вы хотите использовать инъекцию свойств? Можете ли вы рассказать об этом, потому что в большинстве случаев это признак субоптимального дизайна. Пожалуйста, обновите свой вопрос, если хотите. – Steven
Вопрос обновлен. Cheers –