Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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)"}}

like image 949
Usman Khalid Avatar asked Aug 23 '15 16:08

Usman Khalid


1 Answers

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().

like image 88
Steven Avatar answered Sep 30 '22 04:09

Steven