I am working on a large legacy C# application and a task assigned to me is to remove all usages of a static factory class ServiceLocator.GetObject<T>()
and replace with constructor injected dependencies throughout.
For the most part, this is simple, however there are around 50 cases in the application codebase where this is a bit tricky. For instance, Servicelocator
is used in a static class, or extension method, or even a WPF MarkupExtension!.
For instance, if you were faced with a code snippet like this, what would you do? (apart from cry)
public static class MyExtensions
{
private static ISingletonServiceOne _ServiceOne = null;
private static ISingletonServiceTwo _ServiceTwo = null; // etc ...
public static SummaryHeader GetBannerSummary(this IModel rfq, object requester)
{
Guard.ArgumentNotNull(rfq, "rfq");
Guard.ArgumentNotNull(requester, "requester");
if (_ServiceOne == null)
{
_ServiceOne = ServiceLocator.GetService<ISingletonServiceOne>(requester);
Guard.ArgumentNotNull(_ServiceOne, "_ServiceOne");
}
return _ServiceOne.GetBannerSummary(rfq);
}
In the above the ServiceLocator.GetObject() method has been used in an Extension Method on IModel to locate a singleton registered service and execute a method on that using IModel.
The question is:
I am thinking to move the GetBannerSummary() method out of extensions and only IModel in this case, however (don't laugh) there are also cases of the same ServiceLocator being used in ValueConverters (WPF) and MarkupExtensions :0
Your comments/suggestions appreciated
The only time I would ever use ServiceLocator is in static methods, e.g. extension methods, and IValueConverters as, unfortunately, there really isn't any other good way of getting dependencies.
The only (slightly) better solution is to move the ServiceLocator call out to a lazy loaded property, so that the dependency can be injected during unit testing.
In your case, however, that won't fly as you have a requester property being passed to the GetService, in which case you ideally need to add an IServiceOneFactory dependency to which you can pass your requester object. So:
public interface IServiceOneFactory
{
ISingletonServiceOne Create(object requester);
}
public static class MyExtensions
{
public static IServiceOneFactory ServiceOneFactory
{
get
{
if( _ServiceOneFactory==null)
_ServiceOneFactory = ServiceLocator.GetService<IServiceOneFactory>();
return _ServiceOneFactory;
}
set { _ServiceOneFactory = value; }
}
private static IServiceOneFactory _ServiceOneFactory = null;
private static ISingletonServiceOne _ServiceOne = null;
private static ISingletonServiceTwo _ServiceTwo = null; // etc ...
public static SummaryHeader GetBannerSummary(this IModel rfq, object requester)
{
Guard.ArgumentNotNull(rfq, "rfq");
Guard.ArgumentNotNull(requester, "requester");
if (_ServiceOne == null)
{
_ServiceOne = ServiceOneFactory.Create(requester);
Guard.ArgumentNotNull(_ServiceOne, "_ServiceOne");
}
return _ServiceOne.GetBannerSummary(rfq);
}
}