0

Je suis nouveau sur Web API/MVC, Autofac, et DI donc je suis sûr que j'ai le bordel entre les mains .Une erreur est survenue lors de la tentative de création d'un contrôleur de type: DI ne va pas enregistrer l'interface

J'ai un contrôleur dans lequel j'essaie d'injecter une dépendance d'interface de service.

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


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

     /* 
     Routes 
     */ 
    } 

Le contrôleur met en oeuvre une commande de base:

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>(); 
      } 
     } 
    } 

Lorsque vous effectuez un appel à un itinéraire dans le GameBoardController qui utilise le _service, je reçois l'erreur suivante:

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

Si Je fais un appel à un itinéraire qui n'utilise pas le service, ça marche bien. J'utilise Autofac pour gérer mon DI et j'ai essayé d'innombrables tentatives pour obtenir l'enregistrement IGameBoardService; au point que j'ai à peu près épuisé tout ce que je pouvais penser à chercher sur SO ou Google.

Bien sûr, si je fais ce que dit l'erreur et ajoute le constructeur sans paramètre, l'erreur disparaît, mais _service est toujours nulle.

Actuellement, voici comment configurer mon Autofac. J'ai une classe de configuration pour gérer l'ensemble des inscriptions:

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()); 
     } 
    } 

Et le StandardModule se présente comme suit:

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(); 
     } 
    } 

Puis dans mon WebApiConfig je fais un appel à AutofacConfig.RegisterAutoFac();

Si je mets un point d'arrêt dans le AutofacConfig, il est frappé au démarrage, donc je sais qu'il est en cours d'exécution. De toutes les informations que j'ai recueillies, je pense avoir tout ce dont j'ai besoin, mais je ne peux évidemment pas le faire fonctionner. C'est probablement mon manque de familiarité avec tout ce qui me manque quelque chose, mais je suis perdu. J'ai suivi des exemples et des tutoriels et plusieurs threads SO, mais rien ne fonctionne.

Qu'est-ce qui me manque ici pour que _service soit utilisable dans mon contrôleur?

Informations supplémentaires - Je ne sais pas si cela est nécessaire ou non, mais voici mon GameBoardService et son interface:

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(); 
    } 
+1

Avez-vous manqué builder.RegisterApiControllers (Assembly.GetExecutingAssembly()); ? http://docs.autofac.org/fr/latest/integration/webapi.html#quick-start –

Répondre

0

Comme christophe.chapron mentionné, vous devez vous inscrire séparément vous contrôleurs API pour le MVC des contrôleurs avec la ligne suivante:

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

comme décrit dans documentation.