在Controller的构造函数外部使用依赖注入

see*_*_87 7 c# dependency-injection asp.net-mvc-3

所以这就是问题,我的mvc3项目使用依赖注入,并有一个基本的通用IRepository类,其他存储库派生自此类.

所以我可以提前做并在控制器中执行此操作:

public class SomethingController
{
    IOrderRepository repository;

    public SomethingController(IOrderRepository repo)
    {
        this.repository = repo;
    }

    public ActionResult SaveOrder(Order order)
    {
        repository.add(order)
        unitOfWork.CommitChanges();  // THIS works!
    }
}
Run Code Online (Sandbox Code Playgroud)

但现在我需要在这样的自定义静态非控制器中使用其中一个存储库:

static class OrderParser
{
    private IOrderRepository repo;

    public static DoWork()
    {
        repo = DependencyResolver.Current.GetService<IOrderRepository>();

        var ordersInDB = repo.GetAllOrders(); //THIS works!

        //But!
        var ordersForInsertion = new List<Order>();


        //do some backgroundworker magic                     
        //fetch txt files from an ftp server
        var ordersForInsertion = ParseTextFilesIntoOrders();

        foreach order in ordersForInsertion 
             repo.add(order)
        unitOfWork.CommitChanges();
        // THIS doesnt commit anything into the database
        // It also doesnt throw any exceptions
        // and repo isnt null or any of that
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,作为测试,我尝试过:

repo = DependencyResolver.Current.GetService<IOrderRepository>();
Run Code Online (Sandbox Code Playgroud)

在第一个例子中的控制器类内部,看它是否也没有提交东西,并且它没有.(以正确的方式执行[通过构造函数注入存储库和unitOfWork]工作!)

所以它必须与DependencyResolver有关,对吧?

注意:如果还有更多的代码需要我发布,请立即离开,我会在这里快速编辑它!

注2:Thanx!

EDIT1:

关于w0lf的超快速答案以下是一些更多信息:

我的OrderParser类包含一个backgroundWorker,它应该是:

  • 睡了一个小时
  • 列出FTP服务器中的所有文件(纯文本文件).
  • 丢弃已经解析到db中的那些.
  • 将新文件解析为Order对象.
  • 将对象提交到db.
  • 一遍又一遍地开始,直到电源熄灭或者什么:)

所有这一切都必须在没有任何用户操作的情况下发生,这意味着该操作不是来自控制器,因此我所做的就是:

在我的bootstrapper类中

Initialise()
{
    //Unrelated stuff
    OrderParser.DoWork()
}
Run Code Online (Sandbox Code Playgroud)

这就是为什么我将它作为静态类实现(很容易变为非静态)

EDIT2:

它会是这样的:

class OrderParser
{
    private IOrderRepository repo;

    public OrderParser(IOrderRepository foo)
    {
        this.repo = foo;
    }
    public static DoWork()
    {
        //use repo var!
    }
}
Run Code Online (Sandbox Code Playgroud)

但是当我在bootstrapper Initialize()方法中实例化时,我该怎么做,例如:

class bootstrapper
{
    Initialize()
    {
        var parser = new OrderParser(/*how do i pass the dependency here?*/)
        parser.DoWork();
    }
}
Run Code Online (Sandbox Code Playgroud)

EDIT3:

这里有一些更多的测试,请耐心等待!

这是我的OrderParser:

class OrderParser
{
    public OrderParser(IOrderRepository foo, IContext unitOfWork)
    {
        foo.getall(); 

        foo.add(some_order);
        unitOfWork.commit(); 

    }
}
Run Code Online (Sandbox Code Playgroud)

测试1:

public class SomeController
{
    IOrderRepository repository;

    public SomeController(IOrderRepository repo)
    {
        this.repository = repo;
    }

    public ActionResult SomeMethod(Order order)
    {
        repository.GetAll();    //WORKS

        repository.add(order)
        unitOfWork.CommitChanges();  // WORKS
    }
}
Run Code Online (Sandbox Code Playgroud)

TEST2:

class bootstrapper
{
    Initialize()
    {
        //Build unity container..
        //set resolver..

        var parser = new OrderParser(container.Resolve<IOrderRepository>, container.Resolve<IContext>)
        //can getAll, cant commit.
    }
}
Run Code Online (Sandbox Code Playgroud)

TEST3:

public class SomeController
{
    IOrderRepository controllers_repository;

    public SomeController(IOrderRepository repo)
    {
        this.controllers_repository = repo;
    }

    public ActionResult SomeMethod(Order order)
    {
        var parser = new OrderParser(DependencyResolver.Current.GetService<IOrderRepository>,
        DependencyResolver.Current.GetService<IContext>)   
        //can do getall, no commits


        var parser = new OrderParser(controllers_repository, controllers_icontext)
        // obviously works (can getall and commit)
    }
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,当我说"不能提交"时,它不是我得到一个例外或者存储库是null,nope.代码运行好像没关系,只有DB不会改变.

Cri*_*scu 5

一种可能的解决方案是使OrderParser类非静态,并在Controller的构造函数中注入它的一个实例,以触发action(DoWork).

然后make OrderParser的构造函数接受IOrderRepository参数,IoC容器很乐意处理它.

另外,要注意以下事项:

DependencyResolver.Current.GetService<ISomeInterface>();
Run Code Online (Sandbox Code Playgroud)

这称为服务定位器,它被认为是反模式.尽可能避免使用它.

基本上,您应该参考的唯一地方DependencyResolver.Current.GetService是您的实现,IControllerFactory它首先启用DI.

更新:

如果你在另一个应用程序中执行此操作最好,而不是MVC网站.两种选择是:

  • 基于计时器执行该操作的Windows服务
  • 每小时使用Windows任务计划程序运行的控制台应用程序

这些是独立的应用程序将有自己的组合根,可以处理对象实例化/依赖注入问题.

但是,如果您不得不通过Web应用程序执行此操作(例如 - 您拥有仅允许Web应用程序的托管),那么您可能会发现"不要直接使用Dependencey Resolver"的例外情况可以接受"在应用程序启动时规则并做这样的事情:

var runner = DependencyResolver.Current.GetService<OrderParsingRunner>();
runner.StartWorking();
Run Code Online (Sandbox Code Playgroud)

当然,这个OrderParsingRunner类看起来像这样:

public class OrderParsingRunner
{
    private readonly OrderParser orderParser;

    public OrderParsingRunner(OrderParser orderParser)
    {
        this.orderParser = orderParser;
    }

    public StartWorking()
    {
        TaskFactory.StartNew(() => 
            { 
                DoWorkHourly();
            });
    }

    private DoWorkHourly()
    {
        while(true)
        {
            Thread.Sleep(TimeSpan.FromHours(1));

            orderParser.DoWork();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

免责声明:我实际上没有编译/运行这段代码,我只是写它来说明这个概念.

请注意,这是一种解决方法,而不是实际的解决方案.如果可能,建议您使用其他应用程序执行后台任务.