1

Just to give a quick background:

  • It works locally, but not when deployed to the server (windows server 2002) via TeamCity and Octopus
  • I have extracted the nuget packge generate by TC and published locally, and also works fine
  • I have googled a lot in the past few days
  • Have tried many solutions
  • My deployed Api run under specific AppPool
  • My local machine is a Windows 10

I have an web api application, coded on .net framework 4.6, and have some dependency injection using Unity on one of my controllers. I am registering the dependencies on the WebApiConfig, in the Register method, as it follows:

public static void Register(HttpConfiguration config)
{
        // Web API configuration and services
        var container = new UnityContainer();

        var logger = new LoggerFactory().CreateLogger();
        container.RegisterInstance(logger);

        container.RegisterType<IEventStoreConnection>(new InjectionFactory(c => PaymentRegistry.CreateEventStoreConnection(logger)));

        container.RegisterType<IAggregateRepository, AggregateRepository>(new HierarchicalLifetimeManager());
        container.RegisterType<IPaymentRepository, PaymentRepository>(new HierarchicalLifetimeManager());
        container.RegisterType<ICertificateRepository, CertificateRepository>(new HierarchicalLifetimeManager());
        container.RegisterType<ISaxoCallMetadataRepository, SaxoCallMetadataRepository>(new HierarchicalLifetimeManager());

        container.RegisterType<ISaxoCallMetadataService, SaxoCallMetadataService>(new HierarchicalLifetimeManager());
        container.RegisterType<ISaxoConvert, SaxoConvert>(new HierarchicalLifetimeManager());
        container.RegisterType<IPackageService, PackageService>(new HierarchicalLifetimeManager());
        container.RegisterType<ISaxoValidationStageOneService, SaxoValidationStageOneResponseService>(new HierarchicalLifetimeManager());
        container.RegisterType<ISaxoValidationStageTwoService, SaxoValidationStageTwoResponseService>(new HierarchicalLifetimeManager());
        container.RegisterType<ISaxoValidationService, SaxoValidationService>(new HierarchicalLifetimeManager());
        container.RegisterType<ISaxoEndOfDayResponseService, SaxoEndOfDayResponseService>(new HierarchicalLifetimeManager());
        container.RegisterType<ISaxoService, SaxoService>(new HierarchicalLifetimeManager());

        container.RegisterType<IAggregateRoot, PaymentAggregate>(new HierarchicalLifetimeManager());
        container.RegisterType<IExceptionLogger, SerilogExceptionLogger>(new HierarchicalLifetimeManager());
        container.RegisterType<IAuthenticationService, AuthenticationService>();

        // Web API routes
        config.DependencyResolver = new UnityResolver(container);
        config.MapHttpAttributeRoutes();

        config.Filters.Add(new GlobalExceptionFilterAttribute());
        config.Filters.Add(new AuthorizeAttribute());
        config.Filters.Add(new ApiKeyAuthenticationFilter(container.Resolve<IAuthenticationService>()));

        config.Services.Add(typeof(IExceptionLogger), container.Resolve<IExceptionLogger>());

        config.Formatters.Remove(config.Formatters.XmlFormatter);
        config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "{controller}/{action}/{batchPaymentId}",
            defaults: new { batchPaymentId = RouteParameter.Optional }
        );
 }

When I make a request with Postman, I am getting that famous Make sure that the controller has a parameterless public constructor error:

{
    "message": "An error has occurred.",
    "exceptionMessage": "An error occurred when trying to create a controller of type 'SaxoPaymentController'. 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.<SendAsync>d__1.MoveNext()",
    "innerException": {
        "message": "An error has occurred.",
        "exceptionMessage": "Type 'Payments.SaxoIntegration.Api.Controllers.SaxoPaymentController' 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)"
    }
}

Anyone has any idea of how to fix it? Let me know if you need further details on that.

user2761172
  • 31
  • 1
  • 5
  • How are you hosting it locally vs on the server? Where is your Register method called from? Depending on your hosting environment and where you are calling this from, it may just not be getting called. I'd recommend adding some logging here to confirm that it is being called. – Kell Oct 10 '17 at 09:46
  • Related (and possibly a duplicate): https://stackoverflow.com/questions/24254189/make-sure-that-the-controller-has-a-parameterless-public-constructor-error – Steven Oct 10 '17 at 09:51
  • @Steven, it is not duplicated since it works locally, the problem is when deployed to the server – user2761172 Oct 10 '17 at 09:54
  • 1
    Still I think that link gives you the answer, since "what happened is that you didn't register your controllers explicitly in your container". – Steven Oct 10 '17 at 09:55
  • @Kell locally, I created a web application on IIS and pointed to my project folder, and also tried publishing the dlls and stuff to a folder and then pointing to that. Both ways work locally. On the server is hosted on IIS. TeamCity is doing the building/nuget packaging, and then via Octopus I am deploying it. Both local machine and server have the same .net frameworks installed. The log is a good shout though - gonna put some in the Register method. – user2761172 Oct 10 '17 at 09:56
  • "it works locally" means nothing. Run your local website under proper IIS, not IIS express and see if you can replicate the problem – Andrei Dragotoniu Oct 10 '17 at 09:56
  • It is under "proper IIS" @AndreiDragotoniu. Version 10.0.15063.0 to be more specific. I am not just running from VS. Try to read my comments here before posting something next time please. – user2761172 Oct 10 '17 at 10:09

1 Answers1

1

So just an update here for who face the same issue. I have fixed that replacing the two lines below:

container.RegisterType<IEventStoreConnection>(new InjectionFactory(c => PaymentRegistry.CreateEventStoreConnection(logger)));

container.RegisterType<IAggregateRepository, AggregateRepository>(new HierarchicalLifetimeManager());

for this one:

container.RegisterType<IAggregateRepository, AggregateRepository>(new HierarchicalLifetimeManager(), new InjectionConstructor(PaymentRegistry.CreateEventStoreConnection(logger)));

The AggregateRepository class has a constructor getting an IEventStoreConnection as parameter, so the point here was replacing the InjectionFactory implementation by a InjectionConstructor.

user2761172
  • 31
  • 1
  • 5