Service locator for optional dependencies
I just found myself doing an optional dependency service location, which got on my nerve the second that I had to deal with it. I added this tiny tidbit to make it easier:
ILogger logger = IoC.TryResolve<ILogger>(new NullLogger()); logger.WarnFormat("Could not find a enities group for entity: {0}", typeof(TEntity).FullName);
Comments
I'm not sure I understand. Wouldn't it have been better to just set put NullLogger in the IoC container in the first place? Doesn't this kinda defeat the purpose of IoC? Perhaps better would be to extend the container much like the auto mocking container to provide a NullService for non resolvable dependencies.
Joshua,
Yes, it would.
The problem is that I am writing a library, and I don't want to force the users of the library to define certain things on the container.
Can you explain the use cases of IoC.Resolve<>?
The thing I do not completely understand is which classes get their dependencies through dependency injection and which use Resolve?
It is used for service location, mostly.
I don't like it, but it is really useful when you want to use IoC on things like static classes.
If I understand correcly, you end up with two different mechanisms to get your dependencies depending whether they're optional or not.
That's why I prefer to fo with a service locator all the way.
Francois,
Absolutely not.
If I want to use optional dependencies using DI (like I should), I just put a property.
This is for infrastructure concerns more than anything else
Ok, I probably don't have the same definition of "optional" dependency.
Let's say logging is something I just do when exceptions are thrown. If exceptions never happen, I don't need an instance of ILogger.
With Ioc, dependencies are resolved at config time. WIth service locator, they are resolved at runtime, on demand.
Ioc:
try { ...}
catch (Exception ex) { MyInjectedLogger.Log(ex); }
ServiceLocator:
try { ...}
catch (Exception ex) { SerivceLocator.Resolve<ILogger>.Log(ex); }
Francois,
I really don't like this approach. It is opaque, it hides the dependencies and it makes it easier to fail late rather than early.
Given, it hides dependencies. They aren't enforced.
So are method calls on dynamic languages.
For dynamic languages, people argue that it is good test coverage that ensures success...
Couldn't it be the same thing for service locator?
There are some pros and cons to any approach.
Cons of Service Locator are definitely related to how explicit are the dependencies.
Pros are lazy creation of depencies (I find app initialization time to be generaly better)
Also, I've been using extensions methods on IServiceLocator to ease cross-cutting concern usage.
e.g.
interface IServiceLocator { T Resolve<T>(); }
interface IServiceLocatorClient { IServiceLocator Locator { get; set; }}
public static class LoggerExtensions
{
public static void Log(this IServiceLocatorClient client, string msg)
{
}
}
With IoC:
public class Foo : IServiceLocatorClient
{
public IServiceLocator { get; set; } //THE only dependency that has to be injected.
void Do()
{
catch (Exception ex) { this.Log(exception.Message); }
}
}
Comment preview