1

Lets say I have a method which requires a static property and I want to create unit tests, so I wrap it in a wrapper class. Let's call the interface IFoo & concrete class Foo.

Now if my method is called from within an MVC view, how do you get the wrapper instance into that method?

Obviously, I can add an IFoo parameter to my controller constructor, an IFoo property to my view model, and an IFoo parameter to my method, then pass it down the chain; controller, view model, view, extension method. That doesn't seem acceptable me.

So is there a cleaner way to do this?

I assumed a DI Container was the way to go. To be honest, I haven't needed one up until now, and I naively assumed I would just add Ninject, bind concrete types to interfaces, and make the following call within my method.

var dt = kernel.Get<IFoo>();

I assumed this would help me to avoid the entire constructor parameter / property trail mentioned above. Now I knew I'd still need to get the kernel variable from somewhere, but I thought I remembered seeing something about invoking it with thread/session/request scope. I thought I could instantiate the same instance of the kernel regardless of where it was invoked, but when I looked into it I found out that is only for the object instances the kernel is invoking ... not the kernel itself.

So, Is there any way to get an instance of Foo into the method without passing it through a bunch of objects which do nothing but pass it?

John MacIntyre
  • 12,910
  • 13
  • 67
  • 106
  • Can you make it more concrete please? You're claiming this has happened a few times - surely you can give (even a contrived) code example? It's also hurting my head to figure out what you mean by ' I found out that is only for the object instances the kernel is invoking ... not the kernel itself. ' – Ruben Bartelink Apr 21 '13 at 23:10
  • @RubenBartelink - The first revision has a fairly concrete example. See http://stackoverflow.com/revisions/16124853/1 – John MacIntyre Apr 24 '13 at 21:59
  • @RubenBartelink - As far as the kernel sentence goes, what I meant was, that I knew that I could do kernel.Bind().ToSelf().InRequestScope(); to get the same Foo throughout the request, but there wasn't any way to get the same kernel throughout the request. So I'd have to pass the kernel all the way through the trail I mentioned in the question. So I gain nothing. Does that make sense? – John MacIntyre Apr 24 '13 at 22:25
  • 1
    Ah, the first revision instantly made sense to me. I was probably scanning too quickly - it's entirely possible all versions are fine! Here's a +1 as it describes a real problem clearly and the current version seems to too. – Ruben Bartelink Apr 24 '13 at 23:11
  • slightly related: http://stackoverflow.com/questions/1651174/ninject-how-do-i-inject-into-a-class-library – Ruben Bartelink Apr 24 '13 at 23:46

3 Answers3

1

Since I don't know your exact use case what I might suggest may or may not be appropriate. There are a couple of ways that I've handled this and it depends on where you are testing. From the extension method point of view, I think you can just have it take a DateTime and manually inject appropriate values in your unit tests for the extension. If it needs to test a value against DateTime.UtcNow, that's a bit different but you can handle it with a nullable DateTime that defaults to DateTime.UtcNow if you don't supply on in a second parameter.

   public static IHtmlString RegularExtension(this HtmlHelper helper, DateTime when)
   {
      ...
   }

   public static IHtmlString ComparisonExtension(this HtmlHelper helper, DateTime when, DateTime? now = null)
   {
       var nowDate = now ?? DateTime.UtcNow; // verified by inspection, tests use specified values
       ...
   }

or, for the latter, if you don't feel comfortable with the null coalescing operator, use two methods. A public one that takes a single parameter and a private one that uses both. Test your private method using reflection, have the public one simply delegate to the private one. You might also consider using a single method where both parameters are required and always build both values into your model.

From the perspective of the controller, if you need to use a consistent value for the current time, you could inject the wrapper into the controller and have the model populated with the "unwrapped" value from the wrapper. That way you can test that the controller properly sets the value on the model without having to tie everything downstream to the wrapper. The key is that all your code uses the injected (and unwrapped) value instead of calling DateTime.UtcNow directly. From the perspective of the tests on those classes, they don't know where the value comes from, just that it's supplied from upstream.

   public FooController(IDateTimeWrapper timeWrapper)
   {
       var model = new FooModel { Now = timeWrapper.Unwrap(), ...  };

       ...

       return View(model);
   }
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • Thanks Tim, but while the DateTime example is somewhat real, I was using it mostly to illustrate a problematic pattern I'm seeing everywhere. It's more about how do I avoid passing my object through a bunch of classes that aren't using it other than to pass it. Does that make sense? – John MacIntyre Apr 20 '13 at 23:25
  • @JohnMacIntyre I understand but there is a key principle here: wherever possible have your dependencies provide values to lower level components rather than propagate the dependency. Specifically, when it comes to the view, you really should have all the data you need as values. The other alternative is to use `DependencyResolver.Current.GetService()`, http://bradwilson.typepad.com/blog/2010/10/service-location-pt5-idependencyresolver.html, and `DependencyResolver.SetResolver` in your tests. – tvanfosson Apr 21 '13 at 14:14
  • Thanks. I get the idea that higher level functionality should be passing IFoo in, but the idea of creating a field in the controller to do nothing but carry an object from controller to *one* action methods view model just seems to be poor design. I mean aren't properties & fields supposed to have a high cohesion in the class? I thought a DI Framework was supposed to allow you to manage this better. – John MacIntyre Apr 24 '13 at 22:43
  • Let me ask you something; I get how a DI Framework allows you to get around `new A(new B(new C()))` and default constructors like `public A() : this (new X(), new Y(), new Z()) {}`, but is there any other value? I mean this doesn't seem like enough to add another dependency to an app for, but everybody uses them, which leads me to believe I might be missing something. (sincerity intended) – John MacIntyre Apr 24 '13 at 22:50
1

If your ViewModel or View is created by Ninject as well, you should be able to add IFoo as a constructor dependency and get it injected. If you want to directly access the Kernel and resolve an instance (which is usually not the best idea) you can inject an IResolutionRoot and call Get on it.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
treze
  • 3,159
  • 20
  • 21
  • Undid my +1. This is bad advice - do not create ViewModels via DI, also do not inject `IResolutionRoot`s into anything that isnt actually a Factory. The reason for my original +1 was that you did address how one would pass stuff down down the chain (the Abstract Factory point in my answer) – Ruben Bartelink Apr 24 '13 at 23:31
  • What's bad about getting the ViewModels created by DI? I agree on not using IResolutionRoot, I mentioned it's usually not a good idea – treze Apr 25 '13 at 09:06
  • In general, the Model should be the one owning the Responsibility / business logic, a ViewModel should adapt things to a View. While this doesnt have to translate into a hard and fast rule that everything needs to be flattened out into value objects, my point is that you can (and should) be using a lot more `new` and a lot less Abstract Factory to generate ViewModels in general. I know there are counterexamples and am def not downvoting. See http://stackoverflow.com/questions/4835046/why-not-use-an-ioc-container-to-resolve-dependencies-for-entities-business-objec – Ruben Bartelink Apr 25 '13 at 11:47
  • Sadly my google fu is failing wrt finding a decent citation walking through the tradeoffs properly - http://stackoverflow.com/a/8136059/11635 http://stackoverflow.com/questions/6297322/dependency-injection-use-with-data-transfer-objects-dtos – Ruben Bartelink Apr 25 '13 at 11:48
  • Sure, a Model manipulates somehow a ViewModel (simplified) which should have no logic in it. And if I got you right you say the Model should create this ViewModel with new and not getting it injected or use a factory? How do you test the Model? Without exposing the ViewModel to the public? – treze Apr 25 '13 at 14:42
  • 1
    +1 reinstated, you have suggested many cases which are on the valid side so I can no longer hold my line on it being universally bad advice. (I was taking the the term ViewModels as meaning the degenerate case where we're talking about a DTO that will just be rendered - not actually MVVM stuff where a long-lived relationship makes lots of sense). Thanks for bearing with me; I hope @JohnMacIntyre found some of the discussion (and/or either of our answers) useful... – Ruben Bartelink Apr 25 '13 at 14:53
  • Thanks for the clarification. If I hear ViewModel I automatically assume MVVM pattern and therefore was a bit confused. Now I understand your point and I agree that you don't need to create short living DTO by DI. – treze Apr 25 '13 at 15:47
  • Thanks for the debate guys. For the record, when I said ViewModel, I meant DTO ... sorry for the confusion. – John MacIntyre Apr 25 '13 at 17:15
1

First, buy http://manning.com/seemann -- you won't regret it.

In general, the problem of "I'm here in my object tree, give me the X" is addressed in one of the following ways:

  • Constructor Injection - any object that needs an X, asks for it at construction time. See Injection Patterns in the Ninject Wiki
  • Service Location - everyone can always scream at a central mother figure to get stuff - i.e. keeping a ref to a container in a static and calling it willy nilly - see the ploeh article of the same name
  • Abstract Factory - you get injected a Func<T> or an interface IXFactory { X CreateX(); } - see the Ninject.Extensions.Factory wiki
  • Method Injection - it gets created somewhere and you pass it around as necessary - see the Dependency Injection in .NET book

You're expecting a bit much of the container to make it magically possible for anyone anywhere to scream, "I want the X", especially in a static class being called from a DTO. Remember, a container doesnt go in and rewrite your IL interceptign calls to new. In can essentially apply a few Decorators, Factories and Proxies as glue when doing unglamorous wiring stuff together work.

The bottom line is that the appropriate way to handle stuff like this is

  • Anything that needs DI should (and can) not be static, period
  • Short term object instances such as DTOs should not participate in DI (which is not to say one should Compose Object Graphs with confidence even when processing requests - it's just that what you're wiring should be Services, not objects). See Why not use an IoC container to resolve dependencies for entities/business objects?
  • Most of the time you're best off making dependencies explicit via Method Injection and Constructor Injection - that way it pushes your requirements to the surface rather than creating an out of band communications rats nest via Service Location

The last point is critical - by surfacing the real dependencies and listening to them, you'll end up figuring out where the Time Service, Scheduler or Formatter (or whatever the higher level abstraction that's missing in your case) should live over time.

I strongly suggest reading Mark Seemann's top answers around here as most of these important questions and topics are addressed in depth across them, without relying on oversimplified explanations as my answer does. Of course the book itself is the best overall use of your time and money though!

EDIT: (Inspired by your comments with @tvonfosson) One key thing a Container can bring to the party (aside from maintaining a single X within a given scope (see Ninject.Extensions.NamedScope wiki) is to be able to skip passing indirect dependencies down a hierarchy of services for no reason - i.e. if your Controller depends on a Service which depends on a Scheduler and the scheduler needs a Clock, the Service doesnt need to be talking about Clocks, just Schedulers.

The key thing with Containers is to make sure you don't go too far and then try to abuse them for code that should just be code.

Community
  • 1
  • 1
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
  • Thanks for the answer & your patience. Regarding "One key thing a Container can bring to the party is to be able to skip passing indirect dependencies down a hierarchy of services for no reason" ... that's kind of what I was getting at in my comments to Tim & this question. I realize a DI Container doesn't do anything magic, but I assumed I could just set it up and use it anywhere without passing it around. I've ditched the DI framework in my project for now, and will just pass my objects through the controller constructor until I get the book you recommended. Thanks again. – John MacIntyre Apr 25 '13 at 17:40
  • @JohnMacIntyre Not a bad idea to do Dependency Injection By Hand - it's not a lot of typing and you'll learn plenty. Just don't bother too much with half way houses of too much Bastard Injection. – Ruben Bartelink Apr 25 '13 at 19:42