Constructor dependency injection through unit with parameters from HttpContext

We use the domain to customize the behavior of our application. I will illustrate this with an example:

// default behavior
public class CoreService : IService {
  public virtual string Hello { get { return "Hello"; } }
  public virtual string FavouriteDrink { get { return "Water"; } }
}

// german.site.com
public class GermanService : CoreService {
  public override string Hello { get { return "Gutten tag"; } }
  public override string FavouriteDrink { get { return "Beer"; } }
}

// usa.site.com
public class UsaService : CoreService {
  public override string FavouriteDrink { get { return "Cofee"; } }
}

Services are loaded as follows:

var container = new UnityContainer();
container.RegisterType<IService, CoreService>();
container.RegisterType<IService, GermanService>("german.site.com");
container.RegisterType<IService, UsaService>("usa.site.com");

I use Unity to load mvc controllers. IE:

public class HomeController : Controller {
  private IService m_Service;

  // contructor dependency injection magic - this resolves into "CoreService"
  public HomeController([Dependency]IService service) {
    if (service == null) {
      throw new ArgumentNullException("service");
    }
    m_Service = service;
  } 
}

Is there a way to change the uniform resolution so that it respects the domain? Right now i'm done with

public class HomeController : Controller {
  private IService m_Service;

  // contructor dependency injection magic - a lot less magical
  public HomeController() {
    m_Service = DomainServiceLocator.Retrieve<IService>();
  } 
}

Support Classes:

public static class DomainServiceLocator {
  private static UnityContainerAdapter adapter; 

  public static T Retrieve<T>() {
    string domain = HttpContext.Current.Request.Url.Host;
    if (adapter.IsServiceRegistered(typeof(T), domain)) {
      return adapter.Resolve<T>(domain);
    }

    return adapter.Resolve<T>();
  }
}

public class QueryableContainerExtension : UnityContainerExtension {
  private List<RegisterInstanceEventArgs> registeredInstances = new List<RegisterInstanceEventArgs>();
  private List<RegisterEventArgs> registeredTypes = new List<RegisterEventArgs>();

  protected override void Initialize() {
    this.Context.Registering += (sender, e) => { this.registeredTypes.Add(e); };
    this.Context.RegisteringInstance += (sender, e) => { this.registeredInstances.Add(e); };
  }


  public bool IsServiceRegistered(Type service, string name) {
    return registeredTypes.FirstOrDefault(e => e.TypeFrom == service && e.Name == name) != null
           || registeredInstances.FirstOrDefault(e => e.RegisteredType == service && e.Name == name) != null;
  }
}

public class UnityContainerAdapter {
  private readonly QueryableContainerExtension queryableContainerExtension;
  private readonly IUnityContainer unityContainer;

  public UnityContainerAdapter()
    : this(new UnityContainer()) {
  }

  public UnityContainerAdapter(IUnityContainer unityContainer) {
    this.unityContainer = unityContainer;

    // adding extensions to unity container
    this.queryableContainerExtension = new QueryableContainerExtension();
    unityContainer.AddExtension(this.queryableContainerExtension);
  }

  public T Resolve<T>(string name) {
    return unityContainer.Resolve<T>(name);
  }

  public T Resolve<T>() {
    return unityContainer.Resolve<T>();
  }

  public bool IsServiceRegistered(Type service, string name) {
    return this.queryableContainerExtension.IsServiceRegistered(service, name);
  }
}
+3
source share
2 answers

I like to use factory injection in these scenarios when solving something at runtime. Essentially, you resolve your type using the domain name:

So, at the root of your composition, you can register as follows:

container.RegisterType<Func<string, IService>>
                (
                    new InjectionFactory(c => new Func<string, IService>(name => c.Resolve<IService>(name)))
                );

Then in your HomeController you can enter a delegate

public class HomeController
{
    private readonly Func<string,IService> _serviceFactory;

    public HomeController(Func<string, IService> serviceFactory)
    {
        if(serviceFactory==null)
            throw new ArgumentNullException("serviceFactory");

        this._serviceFactory= serviceFactory;
    }

    public void DoSomethingWithTheService()
    {
        var domain = this.HttpContext.Uri.Host;                             
        var service = this._serviceFactory(domain);
        var greeting = service.Hello;
    }
}

`` ``

, DI, " ".

.. CoreService , ?

+1

, - @Spencer. factory, factory DI (IUnityContainer ), . " ", ASP.NET(ASP.NET CORE) , , HttpContext, DI .

public interface IFactory<T>
{
    T Retrieve(string domain);
}   

internal sealed class Factory<T> : IFactory<T>
{
    private readonly IUnityContainer _container;

    public Factory(IUnityContainer container)
    {
        _container = container;
    }

    public T Resolve(string domain)
    {
        // this is actually more complex - we have chain inheritance here
        // for simplicity assume service is either registered for given 
        // domain or it throws an error
        return _container.Resolve<T>(domain);
    }
}

// bootstrapper
var container = new UnityContainer();
container.RegisterType<IService, CoreService>();
container.RegisterType<IService, GermanService>("german.site.com");
container.RegisterType<IService, UsaService>("usa.site.com");
container.RegisterInstance<IFactory<IService>>(new Factory<IService>(container));    

public class HomeController : Controller {
  private IFactory<IService> m_Factory;

  public HomeController(IFactory<IService> factory) {
    m_Factory = factory;
  } 

  private void FooBar() {
    var service = m_Factory.Retrieve(this.HttpContext.Uri.Host);
    var hello = service.Hello;
  }   
}

, , , ,

[Domain("german.site.com")]
public class GermanService : IService { ... }

[DomainRoot]
public class CoreService : IService { ... }

[Domain("usa.site.com")]
public class UsaService : CoreService { ... }

, . - - , github.

0

All Articles