1

如何用簡單注射器進行注射劑注射。簡單注射器注射劑

的與Ninject你要做的就是爲每波紋管:

[Inject] 
public IUnitOfWork UnitOfWork { get; set; } 

我怎麼可以做等同於用這個簡單的注射器。我嘗試在網上找到解決方案,但沒有運氣。

爲什麼我要使用屬性注入?

我想使用屬性注入來設置我的基本控制器中的工作單元,以便它將創建一個新的工作單元OnActionExecuting並提交更改OnResultExecuted。這也意味着我不必通過構造函數創建每個新控制器來傳遞UoW。

+3

它是[在文檔](http://simpleinjector.readthedocs.org/en/latest/extensibility.html#overriding-property-injection-behavior) – qujck

+0

爲什麼你想要使用屬性注入?您能否詳細說明這一點,因爲在大多數情況下,這是次優設計的標誌。如果可以,請更新您的問題和相關信息。 – Steven

+0

問題已更新。歡呼聲 –

回答

3

另一種選擇是使用RegisterInitializer方法:

container.RegisterInitializer<BaseControllerType>(controller => 
{ 
    controller.UnitOfWork = container.GetInstance<IUnitOfWork>(); 
} 

它使所有的配置在你的作文根,不污染你的代碼庫具有各種屬性。

更新:(如許)

雖然這是一個直接回答你的問題,我必須向您提供一個更好的選擇,因爲這是一個基類的用法是IMO不正確設計,出於多種原因。

  1. 抽象類能成爲真正的PITA類,因爲它們往往傾向於擁有各類橫切關注
  2. 一個抽象類,財產注射使用時尤爲突出,掩蓋了需要依賴一個神級增長。

專注於第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實現)和視圖之間的層。

+0

這看起來比thanx更好的解決方案。我會給那個去 –

+0

@ShaneVanWyk看到我的更新答案承諾[這裏](http://stackoverflow.com/questions/34984021/sessionperwebrequest-uow-simpleinjector-actionfilterattribute#comment57776338_34984021) –

+0

謝謝你的更新,看起來像一個好的解決方案我會放棄這一點。 –

2

需要創建如下:

首先創建屬性類

[System.AttributeUsage(System.AttributeTargets.Property] 
public class Inject : Attribute 
{ 
} 

然後創建一個自定義屬性的行爲

class PropertySelectionBehavior<TAttribute> : IPropertySelectionBehavior 
where TAttribute : Attribute 
{ 
    public bool SelectProperty(Type type, PropertyInfo prop) 
    { 
     return prop.GetCustomAttributes(typeof(TAttribute)).Any(); 
    } 
} 

最後告訴容器使用自定義的行爲

container.Options.PropertySelectionBehavior = new PropertySelectionBehavior<Inject>(); 

所有剩下要做的就是與屬性裝飾的財產

[Inject] 
public IUnitOfWork UnitOfWork { get; set; }