简体   繁体   中英

How do I specify which registration of an interface to use with a particular mvc controller?

I have two implementations of an interface that in plain old c# would be instantiated like so:

var useCache = bool.Parse(ConfigurationManager.AppSettings["useCache"]);
var oven = useCache
  ? new CachedCookieOven(new CookieOven())
  : new CookieOven();
var controller = new CookieController(oven); // MVC Controller

here is the interface and classes:

public interface ICookieOven {
  IEnumerable<Cookie> Bake();
}

public class CookieOven : ICookieOven {
  public IEnumerable<Cookie> Bake() {
    var list = new List<Cookie>();
    // bake cookies and return them
    return list;
  }
}

public class CachedCookieOven : ICookieOven {
  readonly ICookieOven _oven;

  public CachedCookieOven(ICookieOven oven) { _oven = oven; }

  public IEnumerable<Cookie> Bake() {
    var cookies = GetFromPlate();
    return cookies ?? _oven.Bake();
  }
}

My MVC controller has the following constructor

public class CookieController : Controller {

  readonly ICookieOven _oven;

  public CookieController(ICookieOven oven) { _oven = oven; }

  public ActionResult ViewCookies() {
    var bakedCookies = _oven.Bake();
    return View(bakedCookies);
  }
}

The Bootstrapper class that is created says in the comments that I don't need to register my mvc controller classes

public static class Bootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = BuildUnityContainer();

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));

        return container;
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();    
        RegisterTypes(container);

        return container;
    }

    public static void RegisterTypes(IUnityContainer container)
    {

    }
}

In Unity I have registered both instances. There may be a better way and if so tell me.

public static class Bootstrapper {
  // ...
  private static IUnityContainer BuildUnityContainer() {
    var container = new UnityContainer();
    var useCache = bool.Parse(ConfigurationManager.AppSettings["useCache"]);
    // register
    container.RegisterType<ICookieOven, CookieOven>("oven");
    if (useCache) {
      container.RegisterType<ICookieOven, CachedCookieOven>("cachedOven",
        new InjectionConstructor(container.Resolve<ICookieOven>("oven"));
    }

  }
}

How do I ensure that the correct instance of ICookieOven gets sent to the constructor of the CookieController mvc controller?

Registering types in Unity without a name makes that the default type. If you want to register more than one type, you have to provide a name. The following is the correct way to register my types in the Bootstrapper class:

public static void RegisterTypes(IUnityContainer container)
{
  var useCache = bool.Parse(ConfigurationManager.AppSettings["useCache"]);
  if (useCache) { 
    // named, this is not the default
    container.RegisterType<ICookieOven,CookieOven>("oven");
    // this one is not named and is the default
    container.RegisterType<ICookieOven,CachedCookieOven>(new InjectionConstructor(
      container.Resolve<ICookieOven>("oven")); 
  } else {
    // notice it is not named, it is the default
    container.RegisterType<ICookieOven,CookieOven>();
  }
}

You want to create an object but which one depends on a value only known at runtime. What you need is a factory (couple of examples here ).

To implement this, one approach could be like this: your controller could depend on a IOvenFactory , injected in controller's constructor. When you need the oven you can call _ovenFactory.Create() .

In an IOvenFactory implementation, you could have the logic of how to create, depending on the configuration value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM