Произошла ошибка при попытке создать контроллер типа: DI не зарегистрирует интерфейс

Я новичок в Web API/MVC, Autofac и DI, поэтому я уверен, что у меня в руках беспорядок.

У меня есть контроллер, в который я пытаюсь внедрить зависимость интерфейса службы.

    [RoutePrefix("api/gameboard")]
    public class GameBoardController : BaseApiController
    {
        private readonly IGameBoardService _service;
        private ApplicationDbContext _con = new ApplicationDbContext();


        public GameBoardController(IGameBoardService service)
        {
            _service = service;
        }

        /*
        Routes
        */
    }

Контроллер реализует базовый контроллер:

 public class BaseApiController : ApiController
    {

        private ModelFactory _modelFactory;
        private ApplicationUserManager _AppUserManager = null;
        private ApplicationRoleManager _AppRoleManager = null;

        protected ApplicationUserManager AppUserManager
        {
            get
            {
                return _AppUserManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
        }

        public BaseApiController()
        {

        }

        protected ModelFactory TheModelFactory
        {
            get
            {
                if (_modelFactory == null)
                {
                    _modelFactory = new ModelFactory(this.Request, this.AppUserManager);
                }
                return _modelFactory;
            }
        }

        protected IHttpActionResult GetErrorResult(IdentityResult result)
        {
            if (result == null)
            {
                return InternalServerError();
            }

            if (!result.Succeeded)
            {
                if (result.Errors != null)
                {
                    foreach (string error in result.Errors)
                    {
                        ModelState.AddModelError("", error);
                    }
                }

                if (ModelState.IsValid)
                {
                    // No ModelState errors are available to send, so just return an empty BadRequest.
                    return BadRequest();
                }

                return BadRequest(ModelState);
            }

            return null;
        }

        protected ApplicationRoleManager AppRoleManager
        {
            get
            {
                return _AppRoleManager ?? Request.GetOwinContext().GetUserManager<ApplicationRoleManager>();
            }
        }
    }

При любом вызове маршрута в GameBoardController, который использует _service , я получаю следующую ошибку:

{
  "message": "An error has occurred.",
  "exceptionMessage": "An error occurred when trying to create a controller of type 'GameBoardController'. 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 'LearningAngular.Api.Controllers.GameBoardController' 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)"
  }
}

Если я звоню на маршрут, который НЕ использует эту услугу, он работает нормально.

Я использую Autofac для обработки своего DI и предпринял бесчисленное множество попыток зарегистрировать IGameBoardService для использования; до такой степени, что я в значительной степени исчерпал все, что мог найти для поиска в SO или Google.

Конечно, если я сделаю то, что говорит ошибка, и добавлю конструктор без параметров, ошибка исчезнет, ​​но _service всегда будет нулевым.

В настоящее время именно так я настроил свой Autofac. У меня есть класс конфигурации для обработки всех регистраций:

public class AutofacConfig
    {
        public static IContainer RegisterAutoFac()
        {
            var builder = new ContainerBuilder();

            AddMvcRegistrations(builder);
            AddRegisterations(builder);

            var container = builder.Build();

            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
            GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

            return container;
        }

        private static void AddMvcRegistrations(ContainerBuilder builder)
        {
            //mvc
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
            builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
            builder.RegisterModelBinderProvider();

            //web api
            builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).PropertiesAutowired();
            builder.RegisterModule<AutofacWebTypesModule>();
        }

        private static void AddRegisterations(ContainerBuilder builder)
        {
            builder.RegisterType<GameBoardService>().As<IGameBoardService>();
            builder.RegisterModule(new StandardModule());
        }
    }

И StandardModule выглядит следующим образом:

public class StandardModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            base.Load(builder);

            // obtain database connection string once and reuse by Connection class
            var conn = ConfigurationManager.ConnectionStrings["DBConnection"];

            // Register Connection class and expose IConnection 
            // by passing in the Database connection information
            builder.RegisterType<Connection>() // concrete type
                .As<IConnection>() // abstraction
                .WithParameter("settings", conn)
                .InstancePerLifetimeScope();

            // Register Repository class and expose IRepository
            builder.RegisterType<Repository>()
                .As<IRepository>()
                .InstancePerLifetimeScope();

            builder.RegisterType<GameBoardService>()
                .As<IGameBoardService> ()
                .InstancePerLifetimeScope();
        }
    }

Затем в моем WebApiConfig я вызываю AutofacConfig.RegisterAutoFac();

Если я поставлю точку останова в AutofacConfig, она сработает при запуске, поэтому я знаю, что она проходит через нее. Из всей информации, которую я собрал, я думаю, что у меня есть все, что мне нужно, но, очевидно, я не могу заставить его работать. Вероятно, это мое незнание всего, из-за чего я что-то упускаю, но я в растерянности. Я следую примерам и учебным пособиям и нескольким потокам SO, но ничего не работает.

Что мне здесь не хватает, чтобы сделать _service пригодным для использования в моем контроллере?

Дополнительная информация - не знаю, нужна она или нет, но вот мой GameBoardService и его интерфейс:

public class GameBoardService : IGameBoardService
    {
        private readonly IRepository _repo;
        private GameBoardHelper gameBoard;
        private Cache cache = new Cache();

        public GameBoardService(IRepository repo)
        {
            _repo = repo;
        }

        public bool createGameBoard()
        {
            gameBoard = new GameBoardHelper();
            cache.insertCacheItem("GameBoard", gameBoard);

            return true;
        }

        public List<Card> playCard(int slot, Card card)
        {
            gameBoard = (GameBoardHelper)cache.getCacheItemByName("GameBoard");

            return gameBoard.playCard(slot, card);
        }

        public bool setHand(int player, List<Card> cardList)
        {
            gameBoard = (GameBoardHelper)cache.getCacheItemByName("GameBoard");

            gameBoard.setHand(player, cardList);
            return true;
        }

        public int getTurn()
        {
            gameBoard = (GameBoardHelper)cache.getCacheItemByName("GameBoard");

            return gameBoard.turn;
        }

        public void setTurn(int player)
        {
            gameBoard = (GameBoardHelper)cache.getCacheItemByName("GameBoard");
            gameBoard.turn = player;
        }

        public Slot opponentTurn()
        {
            gameBoard = (GameBoardHelper)cache.getCacheItemByName("GameBoard");

            return gameBoard.opponentTurn();
        }


        public async Task<IEnumerable<GameBoard>> GetGameBoardAsync()
        {
            // execute the stored procedure called GetEmployees
            return await _repo.WithConnection(async c =>
            {
                // map the result from stored procedure to Employee data model
                var results = await c.QueryAsync<GameBoard>("GetEmployees", commandType: CommandType.StoredProcedure);
                return results;
            });
        }
    }

public interface IGameBoardService
    {
        Task<IEnumerable<GameBoard>> GetGameBoardAsync();
        bool createGameBoard();
        List<Card> playCard(int slot, Card card);
        bool setHand(int player, List<Card> cardList);
        int getTurn();
        void setTurn(int player);
        Slot opponentTurn();
    }

person Joseph Robinson    schedule 03.08.2017    source источник
comment
Вы пропустили builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); ? docs.autofac.org/en/latest/integration/webapi. html#быстрый запуск   -  person christophe.chapron    schedule 03.08.2017


Ответы (1)


Как уже упоминалось christophe.chapron, вам необходимо зарегистрировать контроллеры API отдельно для контроллеров MVC со следующей строкой:

builder.RegisterApiControllers(Assembly.GetExecutingAssembly‌​());

как описано в документации.

person tdragon    schedule 03.08.2017