structuremap:使用setter injection

时间:2017-03-27 08:34:12

标签: c# dependency-injection structuremap

我使用structuremap.net作为我的容器。我想将类的所有依赖项作为依赖项对象传递,而不是每个依赖项传递一个参数。

// Dependencies of Controller
class Dependencies {
    public IUserDatabase UserDatabase { get; set; }
    public IProductDatabase ProductDatabase { get; set; }
    // more dependencies ...
}

class Controller {
    Dependencies _d;

    Controller(Dependencies dependencies){
        this._d = dependencies;
    }

    public ActionResult Action() {
        var user = _this._d.GetUserById(10);
        var product = _this._d.GetProductById(20);
        // ...
    }
}

如何通过结构图构建类IUserDatabase的实例时,如何使用setter injection(IProductDatabaseDependencies等)自动设置所有依赖项?

var container = new Container();
// How to configure this in a generic way?
var dependencies = container.GetInstance<Dependencies>();

修改

我的第一个例子似乎没有说明为什么我想要一个完整的对象的setter注入以及为什么这不是一个糟糕的设计选择。

我们有一个自定义Web框架,它采用了ASP.NET MVC的许多原则,但在很多方面也有所不同。与ASP.NET MVC一样,我们在控制器中也有动作和控制器以及组操作。典型代码如下所示:

class MyController {
    public IUserDatabase _userDatabase; 
    public IProductDatabase _productDatabase;
    public IRatingDatabase _ratingDatabase;
    public ICommentsDatabase _commentsDatabase; 

    MyController(IUserDatabase userDatabase, IUserDatabase productDatabase, IRatingDatabase ratingDatabase, ICommentsDatabase commentsDatabase){
        _userDatabase = userDatabase;
        _productDatabase = productDatabase;
        _ratingDatabase = ratingDatabase;
        _commentsDatabase = commentsDatabase;
    }

    public ActionResult Action1(){
        var user = _userDatabase.GetById(10);
        var product = _productDatabase.GetById(20);
    }

    public ActionResult Action2() {
        var ratings = _ratingDatabase.GetById(20);
        var comments = _commentsDatabase.GetById(20);
    }
}

此控制器有两个动作。这些操作都没有使用控制器的所有依赖项。此外,通过构造函数注入将依赖项传递给控制器​​会产生很多噪音。

相反,我想将一个动作的依赖项直接作为参数传递给该动作。我们有自己的路由,可以轻松支持此功能。

class Action1Dependencies {
    public IUserDatabase UserDatabase {get; set;}
    public IProductDatabase ProductDatabase {get; set;}
}

class Action2Dependencies {
    public IRatingDatabase RatingDatabase  {get; set;}
    public ICommentsDatabase CommentsDatabase  {get; set;}
}

class MyController {
    public static ActionResult Action1(Action1Dependencies d){
        var user = d.UserDatabase.GetById(10);
        var product = d.ProductDatabase.GetById(20);
    }   

    public static ActionResult Action2(Action2Dependencies d) {
        var ratings = d.RatingDatabase.GetById(20);
        var comments = d.CommentsDatabase.GetById(20);
    }
}

因此,我想进行var dependencies = container.GetInstance<Action2Dependencies>();之类的调用,并让StructureMap通过setter注入设置Action2Dependencies的所有属性。

使用C#7并支持tuples,上面的代码也可能成为

class MyController {
    public static ActionResult Action1((IUserDatabase UserDatabase, IProductDatabase ProductDatabase) d){
        var user = d.UserDatabase.GetById(10);
        var product = d.ProductDatabase.GetById(20);
    }   

    public static ActionResult Action2((IRatingDatabase RatingDatabase, ICommentsDatabase CommentsDatabase) d) {
        var ratings = d.RatingDatabase.GetById(20);
        var comments = d.CommentsDatabase.GetById(20);
    }
}

2 个答案:

答案 0 :(得分:0)

正如 @ haim770 建议的那样,您必须在Dependencies类中创建一个期望所有依赖项的构造函数。

但在这种情况下,您只需将问题从控制器移到Dependencies类。

// Dependencies of Controller
class Dependencies {
    public IUserDatabase UserDatabase { get; set; }
    public IProductDatabase ProductDatabase { get; set; }
    // more dependencies ...

    public Dependencies(IUserDatabase userDatabase, IProductDatabase productDatabase)
    {
        UserDatabase = userDatabase;
        ProductDatabase = productDatabase;
    }
}

然后,您的容器代码将起作用。

var container = new Container();
var dependencies = container.GetInstance<Dependencies>();

答案 1 :(得分:0)

这可以通过Setter Injection Policies实现,请参阅http://structuremap.github.io/setter-injection/

var container = new Container(x => {
    x.Policies.SetAllProperties(
        policy => policy.Matching(              
            property => property.DeclaringType == typeof(Dependencies)
    );
});

您还可以更通用的方式定义策略,并为依赖项对象使用标记接口。

interface IDependencies {}
property => typeof(IDependencies).IsAssignableFrom(property.DeclaringType)