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; }