ServiceLocator get instance by passing construction parameter

user845405 picture user845405 · Jun 9, 2015 · Viewed 7.1k times · Source

How can I get object instance with service locator with the constructor below. ProductCode is the constructor parameter used to initialize member properties. For all other constructor parameters, I have registered them using unity in the global.asax file.

Basic way to get object instance if constructor parameters are reference type:

var productSettingsRepo = 
      ServiceLocator.Current.GetInstance<ProductSettingsRepository>();

public ProductSettingsRepository(ILogWriter logWriter, 
          ISecurityFunctionRepository securityRepo,
          IProductSettingsManager productSettingsManager,
          IReferenceDataService referenceDataService, 
          string productCode)
      {
          _logWriter = logWriter;
          _securityRepo = securityRepo;
          _productSettingsManager = productSettingsManager;
          _referenceDataService = referenceDataService;
          ProductInfo = GetProductData(productCode);
      }

Answer

Yacoub Massad picture Yacoub Massad · Oct 31, 2015

The Service Locator pattern is considered an anti-pattern, you might want to refactor to use Dependency Injection.

Having said that, here is one way you can fix your problem without refactoring:

Create a factory interface and class that depends on the service locator to create a ProductSettingsRepository class given the product code like this:

public interface IProductSettingsRepositoryFactory
{
    ProductSettingsRepository Create(string productCode);
}

public class ProductSettingsRepositoryFactory : IProductSettingsRepositoryFactory
{
    public ProductSettingsRepository Create(string productCode)
    {
        return new ProductSettingsRepository(
            ServiceLocator.Current.GetInstance<ILogWriter>(),
            ServiceLocator.Current.GetInstance<ISecurityFunctionRepository>(),
            ServiceLocator.Current.GetInstance<IProductSettingsManager>(),
            ServiceLocator.Current.GetInstance<IReferenceDataService>(),
            productCode);
    }
}

Then make sure that you register this factory with the unity container like this:

unity_container
   .RegisterType<IProductSettingsRepositoryFactory, ProductSettingsRepositoryFactory>();

Then, you can use it like this:

var factory = ServiceLocator
                   .Current
                   .GetInstance<IProductSettingsRepositoryFactory>();

var productSettingsRepo = factory.Create("my product code");