MVC3 - Using dependency injection outside the controller constructor

So here is the problem: my mvc3 project uses Injection Dependency and has a base common class IRepository from which other repositories are derived.

So, I can go ahead and do it in the controller:

public class SomethingController { IOrderRepository repository; public SomethingController(IOrderRepository repo) { this.repository = repo; } public ActionResult SaveOrder(Order order) { repository.add(order) unitOfWork.CommitChanges(); // THIS works! } } 

But now I need to use one of these repositories in a custom static non-controller:

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

So, as a test, I tried to do:

 repo = DependencyResolver.Current.GetService<IOrderRepository>(); 

inside the controller class, as in the first example, to see if it also didn’t pass the material, and it doesn’t. (Doing this the right way [injecting repositories and unitOfWork through constructors] works!)

So this should be due to DependencyResolver, right?

Note: if there is still some code that I need to publish, ask away, and I will edit it here instantly!

Note2: Thanx!

EDIT1:

Regarding quick quick response w0lf Here is some more info:

In my OrderParser class, backgroundWorker is applied, which should:

  • Sleep for an hour
  • List all the files (plain text files) on the FTP server.
  • Discard those already parsed in db.
  • Parse the new files into Order objects.
  • Transfer objects to db.
  • Start all over and over until the power goes out or something :)

All that should happen without any user action, i.e. the action does not come from the controller, so all I do is:

in bootstrapper class

 Initialise() { //Unrelated stuff OrderParser.DoWork() } 

And that's why I implemented it as a static class (easily modifiable for non-static)

EDIT2:

It will be something like:

 class OrderParser { private IOrderRepository repo; public OrderParser(IOrderRepository foo) { this.repo = foo; } public static DoWork() { //use repo var! } } 

But then, when I instantiate it in the bootstrapper initialization method, how would I do it, for example:

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

EDIT3:

Here are some more tests, please, with me.

Here is my OrderParser again:

 class OrderParser { public OrderParser(IOrderRepository foo, IContext unitOfWork) { foo.getall(); foo.add(some_order); unitOfWork.commit(); } } 

Test1:

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

TEST2:

 class bootstrapper { Initialize() { //Build unity container.. //set resolver.. var parser = new OrderParser(container.Resolve<IOrderRepository>, container.Resolve<IContext>) //can getAll, cant commit. } } 

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

By the way, when I say "can not commit", it is not that I am getting an exception, or the repositories are null, nope. the code works as if everything is in order, only the database will not change.

+7
source share
3 answers

One possible solution is to make the OrderParser class non-static and insert an instance of it into the controller constructor that triggers the action ( DoWork ).

Then create an OrderParser constructor with the IOrderRepository parameter, and the IoC container will happily take care of this.

Also, beware of things like:

 DependencyResolver.Current.GetService<ISomeInterface>(); 

This is called the Service Locator, and is considered an anti-pattern . Avoid it if possible.

Basically, the only place you should reference DependencyResolver.Current.GetService is your IControllerFactory implementation, which allows DI in the first place.

Update:

It would be better if you did this in a different application than your MVC website. Two alternatives are possible:

  • Windows service performing this timer-based action
  • A console application that launches using the Windows Task Scheduler every hour

These, being separate applications, will have their own composition roots , which will deal with the problem of object / dependency encapsulation.

If, however, you are forced to do this from your web application (for example, you have a hosting that only allows web applications), then you may consider it acceptable to make an exception to "Do not use Dependencey Resolver directly" and do something like this when starting the application:

 var runner = DependencyResolver.Current.GetService<OrderParsingRunner>(); runner.StartWorking(); 

Of course, the OrderParsingRunner class OrderParsingRunner look OrderParsingRunner like this:

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

Disclaimer: I didn't actually compile / run this code, I just wrote it to illustrate the concept.

Please note that this is a workaround, not an actual solution. He recommended using another application for background tasks, if possible.

+5
source

When using DI, you will not need static helper classes. You can consider everything as a “service” and declare your dependencies in your constructor. This is how I think about it. Then everything is just created for you when you need it.

So, I would change your static class to non-static and introduce it where necessary through the constructor.

Answer for editing 2

Pass your container to the bootstrap class.

 class bootstrapper {  Initialize(DependencyResolver container)  {    var parser = new OrderParser(container.Resolve<IOrderRepository>());    parser.DoWork();  } } 

Edit

I would really do it ...

 var parser = container.Resolve<OrderParser>(); 

and let the dependency resolver choose everything!

+2
source

Since this is a background task, do not run it in a web application. Instead, use utility or scheduled applications on Windows. You will then resolve your link during application initialization or using the [Dependency] attribute

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

+1
source

All Articles