所以这就是问题,我的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!
}
}
但现在我需要在这样的自定义静态非控制器中使用其中一个存储库:
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
}
}
所以,作为测试,我尝试过:
repo = DependencyResolver.Current.GetService<IOrderRepository>();
在第一个例子中的控制器类内部,看看它是否也没有提交东西,但它没有。 (以正确的方式执行[通过构造函数注入存储库和unitOfWork]工作!)
所以它必须与DependencyResolver有关,对吧?
注意:如果您需要我发布更多代码,请立即离开,我会在这里快速编辑它!
注2:Thanx!
EDIT1:
关于w0lf的超快答案 这里有更多信息:
我的OrderParser类包含一个backgroundWorker,它应该是:
所有这一切都必须在没有任何用户操作的情况下发生,这意味着该操作不是来自控制器,因此我所做的就是:
在我的引导程序类
中Initialise()
{
//Unrelated stuff
OrderParser.DoWork()
}
这就是为什么我将它作为静态类实现的原因(很容易变成非静态的)
EDIT2:
这将是:
class OrderParser
{
private IOrderRepository repo;
public OrderParser(IOrderRepository foo)
{
this.repo = foo;
}
public static DoWork()
{
//use repo var!
}
}
但是当我在bootstrapper Initialize()方法中实例化时,我该怎么做,例如:
class bootstrapper
{
Initialize()
{
var parser = new OrderParser(/*how do i pass the dependency here?*/)
parser.DoWork();
}
}
EDIT3:
这是一些更多的测试,请耐心等待我!
这是我的OrderParser:
class OrderParser
{
public OrderParser(IOrderRepository foo, IContext unitOfWork)
{
foo.getall();
foo.add(some_order);
unitOfWork.commit();
}
}
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
}
}
class bootstrapper
{
Initialize()
{
//Build unity container..
//set resolver..
var parser = new OrderParser(container.Resolve<IOrderRepository>, container.Resolve<IContext>)
//can getAll, cant commit.
}
}
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)
}
}
顺便说一句,当我说“不能提交”时,并不是我得到一个例外或者存储库是null,nope。代码运行就像它没关系,只有DB不会改变。
答案 0 :(得分:5)
一种可能的解决方案是使OrderParser
类非静态,并在Controller的构造函数中注入一个触发操作的实例(DoWork
)。
然后让OrderParser
的构造函数获取IOrderRepository参数,IoC容器很乐意处理它。
另外,请注意以下事项:
DependencyResolver.Current.GetService<ISomeInterface>();
这称为服务定位器,它是considered to be an anti-pattern。如果可能,请避免使用它。
基本上,您应该引用DependencyResolver.Current.GetService
的唯一地方是IControllerFactory
的实施,它首先启用了DI。
<强>更新强>
最好是在另一个应用程序中执行此操作而不是MVC网站。两种选择是:
这些作为单独的应用程序将有自己的Composition roots来处理对象实例化/依赖注入问题。
但是,如果您不得不通过Web应用程序执行此操作(例如 - 您拥有仅允许Web应用程序的托管),那么您可能会发现对“不要使用Dependencey Resolver直接“在应用程序启动时统治并做这样的事情:
var runner = DependencyResolver.Current.GetService<OrderParsingRunner>();
runner.StartWorking();
当然,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();
}
}
}
免责声明:我实际上没有编译/运行此代码,我只是为了说明这个概念而编写它。
请注意,这是一种解决方法,而不是实际的解决方案。如果可能,建议您使用其他应用程序执行后台任务。
答案 1 :(得分:2)
使用DI时,您不需要静态辅助类。您可以将所有内容视为“服务”,并在构造函数中声明您的依赖项。这就是我的想法。然后在您需要时为您创建所有内容。
因此,我将静态类更改为非静态类,并通过构造函数将其注入需要的地方。
回答编辑2
将容器传递给bootstrap类。
class bootstrapper
{
Initialize(DependencyResolver container)
{
var parser = new OrderParser(container.Resolve<IOrderRepository>());
parser.DoWork();
}
}
修改强>
我实际上会这样做......
var parser = container.Resolve<OrderParser>();
让依赖解析器解决所有问题!
答案 2 :(得分:1)
由于这是后台任务,因此请勿在Web应用程序中运行此任务。而是在Windows中使用服务或计划的应用程序。 然后,您可以在应用程序初始化期间或使用[Dependency]属性
解析您的引用http://msdn.microsoft.com/en-us/library/zt39148a(v=vs.100).aspx http://stackoverflow.com/questions/888479/using-unity-framework-inject-into-system-windows-forms-form-page