另一种选择是使用RegisterInitializer方法:
container.RegisterInitializer<BaseControllerType>(controller =>
{
controller.UnitOfWork = container.GetInstance<IUnitOfWork>();
}
它使所有的配置在你的作文根,不污染你的代码库具有各种属性。
更新:(如许)
虽然这是一个直接回答你的问题,我必须向您提供一个更好的选择,因为这是一个基类的用法是IMO不正确设计,出于多种原因。
- 抽象类能成为真正的PITA类,因为它们往往倾向于拥有各类横切关注
- 一个抽象类,财产注射使用时尤为突出,掩盖了需要依赖一个神级增长。
专注于第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,尤其是如果您在控制器的操作方法中使用原子操作,则会有更好,更多的设计和更灵活的设计,可以很好地处理这个问题。
我指的是详细描述的命令/处理程序模式here(也读为this for the query part of your application)。
通过这种模式,您不会注入抽象的通用IUnitOfWork
,但会注入特定所需的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());
}
这样可以使你的控制器干净,让它做它必须做什么,即成为业务逻辑(本例中为commandhandler实现)和视图之间的层。
它是[在文档](http://simpleinjector.readthedocs.org/en/latest/extensibility.html#overriding-property-injection-behavior) – qujck
为什么你想要使用属性注入?您能否详细说明这一点,因为在大多数情况下,这是次优设计的标志。如果可以,请更新您的问题和相关信息。 – Steven
问题已更新。欢呼声 –