Simple Injector - Make sure that the controller has a parameterless public constructor on production

26,055

Solution 1

Please take a look at the inner exception of the thrown exception. It contains the details that describes why this is happening.

There are multiple problems here. You should make sure that you register all your root types explicitly in the container. Controllers are root types, because they are resolved directly (nothing depends on them, but they have dependencies). If you don't register them explicitly, the container is unable to check if they can be created when you call Verify(). You can register your controllers by calling the following:

container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

This is described in the documentation.

After doing this, you probably directly see the Verify() method fail when you start the application, and in this case you get a very detailed message explaining what is going wrong.

From the inner exception you can see that Web API's DefaultHttpControllerActivator.GetInstanceOrActivator method is calling TypeActivator.Create<T>(Type). This only happens when the call to request.GetDependencyScope().GetService(controllerType) returns null. But this is typically something that can't happen if you hooked in the SimpleInjectorWebApiDependencyResolver into the Web API pipeline. This is because the SimpleInjectorWebApiDependencyResolver will never return null when it is requested to resolve an IHttpController implementation. Instead it will throw an exception when a controller can't be resolved.

So this to me is an indication of a binding redirect problem in your application. This means that the SimpleInjector.Integration.WebApi.dll is referring to a different IHttpController version than what your application is using. Binding redirects are meant to solve this, so make sure that your application has the correct binding. For the System.Web.Http.dll it looks like this (but note that you might need other bindings as well):

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    ... 
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" 
          culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Usually the bindings are managed by NuGet package manager, but it fails to do so on a regular basis.

When the binding redirect issue is fixed, you'll see that the inner exception contains information that comes from Simple Injector with the same information you'll see when calling Verify().

Solution 2

You are not registering the correct DependencyResolver for WebApi. According to the WebApi Dependency Injection page and the Simple Injector WebApi page, it is supposed to be done like this.

public static void Register(HttpConfiguration config)
{
    var container = new Container();

    container.RegisterWebApiRequest<IRepositoryAsync<Category>, Repository<Category>>();
    container.RegisterWebApiRequest<ICategoryService, CategoryService>();
    container.RegisterWebApiRequest<IDataContextAsync>(() => new MyContext());
    container.Verify();

    config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

    // Other Web API configuration not shown.
}

The configuration you have shown is for MVC dependency injection (which you may also need).

Share:
26,055
Usman Khalid
Author by

Usman Khalid

My name is Usman Khalid. I did Masters in Computer Science in 2009 and since then I have been working as a Software Engineer using technologies like ASP.NET, C#, VB.NET, Windows Azure, Amazon Web Services, JavaScript, JQuery, SQL Server, MySQL etc. I like to know more and more about new things and I like to search for new questions and then find answers for those questions.

Updated on September 05, 2020

Comments

  • Usman Khalid
    Usman Khalid over 3 years

    I am stuck with a strange situation. I am following Onion Architecture and my architecture is something like this:

    1-Core
         - Domain Classes
         - Repository Interfaces
         - Service Interfaces
    2-Infrastructure
         - Data
         - Dependency Injection // Here I am using Simple Injector as dependency injection
         - Repository Interfaces Implementation
         - Service Interfaces Implementation
    3-WebApi
         - Web Api Project
    4-WebClient
         - My AngularJs App
    5-Test
         - Test Project
    

    Dependency Injection:

    [assembly: PreApplicationStartMethod(typeof(IocConfig), "RegisterDependencies")]
    namespace Infrastructure.DependencyResolution
    {
        public class IocConfig
        {
            public static void RegisterDependencies()
            {
                var container = new Container();
    
                container.RegisterWebApiRequest<IRepositoryAsync<Category>, Repository<Category>>();
                container.RegisterWebApiRequest<ICategoryService, CategoryService>();
                container.RegisterWebApiRequest<IDataContextAsync>(() => new MyContext());
                container.Verify();
                GlobalConfiguration.Configuration.DependencyResolver =
                new SimpleInjectorWebApiDependencyResolver(container);
    
            }
        }
    }
    

    Web Api Project:

    public class HomeController : ApiController
    {
        private readonly ICategoryService _categoryService;
        public HomeController(ICategoryService categoryService)
        {
            _categoryService = categoryService;
        }
    }
    

    Everything is working very fine on my local IIS. But now I have published this application to the production server and now it is giving me below error:

    {"message":"An error has occurred.","exceptionMessage":"An error occurred when trying to create a controller of type 'HomeController'. Make sure that the controller has a parameterless public constructor.","exceptionType":"System.InvalidOperationException","stackTrace":" at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()","innerException":{"message":"An error has occurred.","exceptionMessage":"Type 'JetAdz.WebApi.Controllers.HomeController' does not have a default constructor","exceptionType":"System.ArgumentException","stackTrace":" at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"}}