另一種選擇是使用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
問題已更新。歡呼聲 –