autofac / Autofac.WebApi

ASP.NET Web API integration for Autofac
Other
36 stars 27 forks source link

Cannot get Autofac to work with Web API #39

Closed paulsaxton closed 5 years ago

paulsaxton commented 5 years ago

I am struggling to get AutoFac to work with WebApi2 controllers

I always get an error that there is no parameterless constructor


    {
        "Message": "An error has occurred.",
        "ExceptionMessage": "An error occurred when trying to create a controller of type 'GatewayController'. 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__15.MoveNext()",
        "InnerException": {
            "Message": "An error has occurred.",
            "ExceptionMessage": "Type 'Gv8ApiGateway.Controllers.GatewayController' does not have a default constructor".....
        }
    }

I have been through loads of posts on this online and I cant see that I have missed anything

When I look at my container after it has been built I can see that it does contain my controller

I am using TopShelf


        HostFactory.Run(x => //1
        {
            x.UseAutofacContainer(container);

            x.Service<IMyService>(s => //2
            {
                s.ConstructUsingAutofacContainer();
                s.WhenStarted(tc => tc.Start());
                s.WhenStopped(tc => tc.Stop());
            });
            x.SetStartTimeout(TimeSpan.FromMinutes(4));
            x.StartAutomatically();
            x.RunAsLocalSystem();
            x.EnableServiceRecovery(r => { r.RestartService(0); });
            x.SetDescription($"DESCRIPTION");
            x.SetDisplayName($"DISPLAY NAME");
            x.SetServiceName($"NAME");
        });

In my assembly module I have the line which I have verified is being called

builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

In my class that is started by TopShelf I have -


    var resolver = new AutofacWebApiDependencyResolver(_container);
    GlobalConfiguration.Configuration.DependencyResolver = resolver;
    _webApi = WebApp.Start<Startup>("http://localhost:8084");

My Startup class is -


    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Configure Web API for self-host. 
            var config = new HttpConfiguration();

            config.MapHttpAttributeRoutes();

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

            app.UseWebApi(config);

        }
    }

I think the key is the place that I set the dependency resolver but it doesnt seem to make any difference where I call this, i.e. before or after I start the API

My controller is:


    public class GatewayController : ApiController
    {
        private readonly IMyService_myService;

        public GatewayController(IMyService myService)
        {
            Argument.IsNotNull(() => myService);

            _myService = myService;
        }    
    }

Can anyone see what I have done wrong please?

Paul

alexmg commented 5 years ago

Is this an OWIN application? If so, you need to use the HttpConfiguration instance created in the Startup class and not the GlobalConfiguration. See the OWIN specific steps in the documentation.

https://autofac.readthedocs.io/en/latest/integration/webapi.html#owin-integration

tillig commented 5 years ago

This appears to have been double-posted to StackOverflow. We can continue troubleshooting/follow up there to avoid double efforts.