Error: Make sure that the controller has a parameterless public constructor (Autofac, WebApi2, & Onion Architecture)

旧街凉风 提交于 2019-12-11 06:19:46

问题


OK, I am getting the familiar error:

An error occurred when trying to create a controller of type 'UserController'. Make sure that the controller has a parameterless public constructor. ---> System.ArgumentException: Type 'Project.WebApi.Controllers.UserController' does not have a default constructor at System.Linq.Expressions.Expression.New(Type type)

I am building a WebApi2 project (no MVC front end) that use Onion Architecture, putting most of my start-up code in App_Start of a Bootstrap project. Here are the relevant classes:

WebAPI Project Code:

UserController.cs

//[Authorize]
    [RoutePrefix("api/v1")]
    public class UserController : ApiController
    {
        private readonly IMediator _mediator;

        public UserController(IMediator mediator)
        {
            if (mediator == null)
                throw new ArgumentNullException(nameof(mediator), "mediator");
            _mediator = mediator;
        }

        // GET api/v1/users
        [HttpGet]
        [Route("users")]
        public async Task<IEnumerable<User>> Get()
        {

            var users = await _mediator.SendAsync(new AsyncGenericQuery<User>(20));

            return users;

        }

        // Other methods taken out for brevity.

Global.asax

public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AutoMapperConfig.Initialize();
            GlobalConfiguration.Configure(WebApiConfig.Register);

        }
    }

App_Start/WebApiConfig:

public static void Register(HttpConfiguration config)
        {
            // Enable debugging, remove in upper env.
            config.EnableSystemDiagnosticsTracing();

            // Web API configuration and services
            var validatorFactory = new FluentValidatorFactory();
            FluentValidationModelValidatorProvider.Configure(config, provider => provider.ValidatorFactory = validatorFactory);

            // Action Filters
            config.Filters.Add(new FluentValidationActionFilter());

            // Exception Filter
            config.Filters.Add(new ServiceExceptionFilterAttribute());

            config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Never;

            // Web API routes
            config.MapHttpAttributeRoutes();

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


   );
    }
}

Bootstrapper Project Code

App_Start/Startup.cs

public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);

        }
    }

App_Start/Statup.Auth.cs

public partial class Startup
    {
        public static IDataProtectionProvider DataProtectionProvider { get; private set; }

        public void ConfigureAuth(IAppBuilder app)
        {
            DataProtectionProvider = app.GetDataProtectionProvider();

            //Removed auth logic...

        }
    }

App_Start/IocConfig.cs

public class IocConfig
    {
        public static void RegisterDependencies()
        {
            DbContextScopeExtensionConfig.Setup();

            var builder = new ContainerBuilder();

            // Get HttpConfiguration
            var config = GlobalConfiguration.Configuration;

            //builder.RegisterApiControllers(typeof(WebApiApplication).Assembly);

            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            builder.RegisterType<DbContextScopeFactory>().As<IDbContextScopeFactory>().SingleInstance();

            builder.RegisterType<AmbientDbContextLocator>().As<IAmbientDbContextLocator>().SingleInstance();

            // Registers our IMediator (abstraction for observer pattern, which lets us use CQRS)
            builder.RegisterModule(new MediatorModule(Assembly.Load("Project.Services")));

            // Registers our Fluent Validations that we use on our Models
            builder.RegisterModule(new FluentValidationModule(Assembly.Load("Project.WebApi"), Assembly.Load("Project.Services")));

            // Registers our AutoMapper Profiles
            builder.RegisterModule(new AutoMapperModule(Assembly.Load("Project.WebApi"), Assembly.Load("Project.Services")));

            // Registers our Identity
            builder.RegisterModule(new IdentityModule(Assembly.Load("Project.WebApi"), Assembly.Load("Project.Services")));

            var container = builder.Build();

            config.DependencyResolver = new AutofacWebApiDependencyResolver(container);


        }

App_Start/MediatorModule.cs

public class MediatorModule : Module
    {
        private readonly System.Reflection.Assembly[] _assembliesToScan;

        public MediatorModule(params System.Reflection.Assembly[] assembliesToScan)
            : base()
        {
            _assembliesToScan = assembliesToScan;
        }

        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterSource(new ContravariantRegistrationSource());
            builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces();

            // Register our Procedures
            builder.RegisterAssemblyTypes(_assembliesToScan)
                .Where(t => t.GetInterfaces().Any(i => i == typeof(IProcedure)))
                .AsSelf()
                .InstancePerDependency();

            // Register our PreRequestHandler
            builder.RegisterAssemblyTypes(_assembliesToScan)
                .AsClosedTypesOf(typeof(IPreRequestHandler<>))
                .SingleInstance();

            builder.RegisterAssemblyTypes(_assembliesToScan)
                .AsClosedTypesOf(typeof(IAsyncPreRequestHandler<>))
                .SingleInstance();


            builder.ScanRegisterAndDecorate(
                _assembliesToScan,
                typeof(IDatabaseService),
                typeof(IAsyncRequestHandler<,>),
                typeof(AsyncMediatorPipeline<,>),
                typeof(AsyncDbContextScopeBoundary<,>),
                typeof(AsyncValidatorHandler<,>),
                typeof(ExceptionLoggerAsync<,>),
                typeof(AsyncLoggingHandler<,>)
            );

            builder.ScanRegisterAndDecorate(
                _assembliesToScan,
                typeof(IDatabaseService),
                typeof(IRequestHandler<,>),
                typeof(MediatorPipeline<,>),
                typeof(DbContextScopeBoundary<,>),
                typeof(ValidatorHandler<,>),
                typeof(ExceptionLogger<,>),
                typeof(LoggingHandler<,>)
            );

            #region Generic Helper Query Services

            // Special registration of our Automapper Handler
            builder.RegisterGeneric(typeof(AutoMapperQuery<,>)).AsSelf();
            builder.RegisterGeneric(typeof(AutoMapperQueryHandler))
                .As(typeof(IRequestHandler<,>))
                .SingleInstance();

            builder.RegisterGeneric(typeof(AsyncAutoMapperQuery<,>)).AsSelf();
            builder.RegisterGeneric(typeof(AsyncAutoMapperQueryHandler<,>))
                .As(typeof(IAsyncRequestHandler<,>))
                .SingleInstance();

            // Special Registration of our Generic Query Handler
            builder.RegisterGeneric(typeof(GenericQuery<>)).AsSelf();
            builder.RegisterGeneric(typeof(GenericQueryHandler))
                .As(typeof(IRequestHandler<,>))
                .SingleInstance();

            builder.RegisterGeneric(typeof(AsyncGenericQuery<>)).AsSelf();
            builder.RegisterGeneric(typeof(AsyncGenericQueryHandler<>))
                .As(typeof(IAsyncRequestHandler<,>))
                .SingleInstance();

            // Special Registration of our Pagination Query Handler
            builder.RegisterGeneric(typeof(PaginateQuery<>)).AsSelf();
            builder.RegisterGeneric(typeof(PaginateQueryHandler))
                .As(typeof(IRequestHandler<,>))
                .SingleInstance();

            builder.RegisterGeneric(typeof(AsyncPaginateQuery<>)).AsSelf();
            builder.RegisterGeneric(typeof(AsyncPaginateQueryHandler))
                .As(typeof(IAsyncRequestHandler<,>))
                .SingleInstance();

            #endregion

            // Sets the delegate resolver factories for Mediatr.
            // These factories are used by Mediatr to find the appropriate Handlers
            builder.Register<SingleInstanceFactory>(ctx =>
            {
                var c = ctx.Resolve<IComponentContext>();
                return t => c.Resolve(t);
            });
            builder.Register<MultiInstanceFactory>(ctx =>
            {
                var c = ctx.Resolve<IComponentContext>();
                return t => (IEnumerable<object>) c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
            });
        }
    }

Over the Bootstrapper namespace in the IocConfig file, I have:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(IocConfig), "RegisterDependencies")]

This should register my types as part of the application startup process. In this file, I am registering my controllers:

builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

However, my UserController is obviously not getting recognized at startup.

Any idea what I am doing wrong?

来源:https://stackoverflow.com/questions/40005815/error-make-sure-that-the-controller-has-a-parameterless-public-constructor-aut

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!