16

I have a Web API controller that has some resources DI'd. Out of later necessity I have added an MVC controller, now I need same resources DI'd there as well. Here is my original configuration:

    [assembly: WebActivator.PostApplicationStartMethod(typeof(CineplexSearch.App_Start.SimpleInjectorWebApiInitializer), "Initialize")]

namespace CineplexSearch.App_Start
{
    using System.Web.Http;
    using SimpleInjector;
    using SimpleInjector.Integration.WebApi;

    public static class SimpleInjectorWebApiInitializer
    {
        /// <summary>Initialize the container and register it as Web API Dependency Resolver.</summary>
        public static void Initialize()
        {
            var container = new Container();
            container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();

            InitializeContainer(container);

            container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

            container.Verify();

            GlobalConfiguration.Configuration.DependencyResolver =
                new SimpleInjectorWebApiDependencyResolver(container);
        }

        private static void InitializeContainer(Container container)
        {
            container.Register<ICachingManager, CachingManager>(Lifestyle.Transient);
            container.Register<IDataAccessLayer, DataAccessLayer>(Lifestyle.Transient);
        }
    }
}

Can I register DI for MVC Controller in the same place as well? Can I reuse the container?

Update: I must be close, but now I get an error in the Web API controller that I need a parameterless constructor; I tried adding it, but then nothing gets injected of course

public static class SimpleInjectorWebApiInitializer
{
    /// <summary>Initialize the container and register it as Web API Dependency Resolver.</summary>
    public static void Initialize()
    {
        var container = new Container();
        container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();

        InitializeContainer(container);

        container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

        container.Verify();

        //GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
        DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    }

    private static void InitializeContainer(Container container)
    {
        container.Register<ICachingManager, CachingManager>(Lifestyle.Transient);
        container.Register<IDataAccessLayer, DataAccessLayer>(Lifestyle.Transient);
    }
}
FailedUnitTest
  • 1,637
  • 3
  • 20
  • 43

3 Answers3

16

Can I reuse the container?

Yes you can, and you should. Every app domain should typically have one container instance.

The MVC integration documentation of the Simple Injector documentation explains that you should set the MVC DependencyResolver as follows:

DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

To make things easier however, your should register the WebRequestLifestyle as DefaultScopedLifestyle:

container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();

This will work for Web API as well, since you are solely running Web API from within IIS.

So you need to configure both the DependencyResolvers.

Malice
  • 3,927
  • 1
  • 36
  • 52
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thanks for quick reply, I almost have it working, can you please see my update? – FailedUnitTest May 31 '16 at 15:16
  • @FailedUnitTest you need *both* the dependency resolvers. So the Web API dependency resolver as well. – Steven May 31 '16 at 16:02
  • 5
    Just so I completely understand, we should use both `.RegisterMvcControllers()` and `RegisterWebApiControlers()` as well as _both_ `System.Web.Mvc.DependencyResolver(new SimpleInjectorDependencyResolver(container))` _and_ `GlobalConfiguration.Configuration.DependencyResolver(new SimpleInjectorWebApiDependencyResolver(container))`? – Zachary Scott Jul 08 '16 at 15:30
  • 2
    @Dr.Zim: If you use both Web API and MVC: yes. – Steven Jul 08 '16 at 22:09
  • Thank you @Dr.Zim. By your comment, i understood the whole answer. – Edukondalu Thaviti Jan 10 '17 at 12:56
  • An exception is thrown System.TypeLoadException: 'Derived method 'get_Length' in type 'SimpleInjector.Integration.Web.WebRequestLifestyle' from assembly 'SimpleInjector.Integration.Web, Version=2.7.3.0, Culture=neutral, PublicKeyToken=984cb50dea722e99' cannot reduce access.' – Moises Marques Oct 08 '20 at 17:21
  • Wow, still on v2? Please make sure all Simple Injector packages are of the same version. – Steven Oct 08 '20 at 18:10
3

I would like to add my two cents because after reading Steven's answer and the comments below it I still got some errors. Eventually this had to do with the order in which things are getting configured.

protected void Application_Start()
{
    //set the default scoped lifestyle
    Container container = new Container();
    container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();

    ...
    //do class registration here. I did it with Scoped lifestyle
    ...
    //Let the SimpleInjector.Intergration packages register the controllers.       
    container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
    container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

    AreaRegistration.RegisterAllAreas();
    //This must be here because we first need to do above before registering the web api. See WebApiConfig code.
    GlobalConfiguration.Configure(WebApiConfig.Register);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    //don't set the resolver here, do it in WebApiConfig.Register()
    //DependencyResolver.SetResolver(new SimpleInjectorWebApiDependencyResolver(container));
    DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    container.Verify(SimpleInjector.VerificationOption.VerifyAndDiagnose);
}

WebApiConfig:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API routes
        config.MapHttpAttributeRoutes();
        //set the webApi resolver here!
        config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(DependencyInjectionCoreSetup._Container);
        //then the rest..
        var route = config.Routes.MapHttpRoute(
        ....
    }
}
CularBytes
  • 9,924
  • 8
  • 76
  • 101
1

Also be aware that the WebRequestLifestyle() is obsolete at the time . You can use instead:

//...

container.Options.DefaultScopedLifestyle = new SimpleInjector.Lifestyles.AsyncScopedLifestyle();

//...
Bruno Mósca
  • 61
  • 1
  • 2
  • 6
  • WebRequestLifestyle(bool) is obsolete. WebRequestLifestyle() is not obsolete. https://simpleinjector.org/ReferenceLibrary/html/T_SimpleInjector_Integration_Web_WebRequestLifestyle.htm The recommendation is to use AsyncScopedLifestyle in applications that solely consist of a Web API (or other asynchronous technologies such as ASP.NET Core) and use WebRequestLifestyle for applications that contain a mixture of Web API and MVC. https://simpleinjector.readthedocs.io/en/latest/lifetimes.html?highlight=asyncscopedlifestyle#async-scoped-lifestyle-vs-web-request-lifestyle – Aaron Queenan May 19 '20 at 03:04