简单喷射器特性注入 [英] Simple Injector Property Injection

查看:84
本文介绍了简单喷射器特性注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用Simple Injector执行属性注入.

How do you perform property injection with Simple Injector.

使用Ninject进行的操作如下所示:

The with Ninject you do is as per bellow:

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

如何使用Simple Injector做到这一点.我试图在网上找到解决方案,但没有运气.

How can I do the equivalent to this with Simple Injector. I tried finding a solution online but had no luck.

为什么要使用属性注入?

我想使用属性注入在基本控制器中设置工作单元,以便它将创建新的工作单元OnActionExecuting并提交更改OnResultExecuted.这也意味着我不必通过构造函数创建的每个新控制器都传入UoW.

I want to use property injection to set up unit of work in my base controller so that it will create a new unit of work OnActionExecuting and commit the changes OnResultExecuted. It also means I don't have to pass in the UoW with each new controller I create through the constructor.

推荐答案

另一种选择是使用 RegisterInitializer 方法:

Another option is to use the RegisterInitializer method:

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

它将所有配置保留在您的合成根目录中,并且不会使用各种属性来污染您的代码库.

It keeps all configuration in your composition root and does not pollute your code base with all kinds of attributes.

更新 :(按承诺)

虽然这是对您问题的直接答案,但我必须为您提供一个更好的选择,因为出于多种原因,为此使用基类不是IMO的正确设计.

While this is a direct answer to your question I have to provide you with a better option, because the usage of a base class for this is a IMO not the correct design, for multiple reasons.

  1. 抽象类可能会变成真正的PITA类,因为它们趋向于发展为具有各种交叉关注点的上帝类
  2. 一个抽象类,尤其是与属性注入一起使用时,会隐藏所需的依赖项.

关注点2.当您要对从基本控制器继承的控制器进行单元测试时,您无法知道该控制器依赖于IUnitOfWork.您可以通过使用构造函数注入而不是属性注入来解决此问题:

With focus on point 2. When you want to unit test a controller which inherits from the base controller, you have no way of knowing that this controller is dependent on IUnitOfWork. This you could solve by using constructor injection instead of property injection:

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方法中都提交更改.请求完成后,更改只能由上下文保存.以这种方式考虑设计是一件好事,因为保存更改是,或者可以看作是跨领域关注,而您实施此关注的方式或多或少地称为 AOP .

While this solves point 2, point 1 is still lurking. The main reason you're wanting this, as you say, is because you do not want to commit your changes in every Action method. Changes must just be saved by the context when the request is done. And thinking about design in this way is a good thing, because Saving changes is, or can be seen as a cross cutting concern and the way you're implementing this is more or less known as AOP.

如果涉及到 AOP ,特别是如果您正在处理原子动作控制器的操作方法,还有更好得多的 SOLID 和更灵活的设计可能会很好地处理这一问题.

If it's comes to AOP, especially if you're working with atomic actions in the action methods of your controllers, there is a far better, more SOLID and more flexible design possible which deals with this very nicely.

我指的是详细描述的命令/处理程序模式此查询应用程序的一部分).

I'm referring to the Command/Handler pattern which is described in great detail here (also read this for the query part of your application).

使用这种模式,您无需注入通用的IUnitOfWork抽象,而是注入特定的所需ICommandHandler<TCommand>抽象.

With this patterns you don't inject a generic IUnitOfWork abstraction, but inject the specific needed ICommandHandler<TCommand> abstractions.

动作方法将触发负责此特定动作的命令处理程序.所有命令处理程序都可以简单地由单个开放式SaveChangesCommandHandlerDecorator,'ValidationDecorator','CheckPermissionsDecorator'等修饰.

The action methods would fire the responsible commandhandler for this specific action. All commandhandlers can simple be decorated by a single open-generic SaveChangesCommandHandlerDecorator, 'ValidationDecorator', 'CheckPermissionsDecorator', etc...

一个简单的例子:

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

这可以使您的控制器保持整洁,并让它执行必须执行的操作,即成为业务逻辑(在这种情况下为命令处理程序实现)和视图之间的层.

This keeps your controllers clean and let it do what it must do, namely be the layer between the business logic (the commandhandler implementation in this case) and the view.

这篇关于简单喷射器特性注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆