J'essaie de configurer Autofac sur mon projet Web API 2. Je ne l'ai utilisé que quelques fois auparavant. J'ai utilisé Nuget et installé à la fois Autofac et Autofac.WebApi2 . Ensuite, dans ma classe Startup , j'ai fait ceci:

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

        // Get our http configuration
        var config = new HttpConfiguration();

        // Register the Autofac middleware FIRST. This also adds
        // Autofac-injected middleware registered with the container.
        var container = ConfigureInversionOfControl(app, config);

        // Register all areas
        AreaRegistration.RegisterAllAreas();  
        GlobalConfiguration.Configure(WebApiConfig.Register);

        // Use our web api
        app.UseWebApi(config);
    }

    /// <summary>
    /// Configures Autofac DI/IoC
    /// </summary>
    /// <param name="app"></param>
    /// <param name="config"></param>
    private IContainer ConfigureInversionOfControl(IAppBuilder app, HttpConfiguration config)
    {

        // Create our container
        var builder = new ContainerBuilder();

        // You can register controllers all at once using assembly scanning...
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        // Register our module
        builder.RegisterModule(new AutofacModule());

        // Build
        var container = builder.Build();

        // Lets Web API know it should locate services using the AutofacWebApiDependencyResolver
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

        // Return our container
        return container;
    }
}

Le module que j'ai créé ressemble à ceci:

public class AutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {

        // Create our Singletons
        builder.RegisterType<DatabaseContext>().As<DbContext>().InstancePerRequest();

        // Create our Services
        builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
        builder.RegisterType<AnswerService>().As<IAnswerService>().InstancePerRequest();
        builder.RegisterType<CategoryService>().As<ICategoryService>().InstancePerRequest();
        builder.RegisterType<FeedService>().As<IFeedService>().InstancePerRequest();
        builder.RegisterType<FilterService>().As<IFilterService>().InstancePerRequest();
        builder.RegisterType<QuestionGroupService>().As<IQuestionGroupService>().InstancePerRequest();
        builder.RegisterType<StateService>().As<IStateService>().InstancePerRequest();

        // Create our providers
        //builder.RegisterType<AnswerProvider>().As<IAnswerProvider>().InstancePerLifetimeScope();
        builder.RegisterType<CategoryProvider>().As<ICategoryProvider>().InstancePerRequest();
        builder.RegisterType<FeedProvider>().As<IFeedProvider>().InstancePerRequest();
        builder.RegisterType<FilterProvider>().As<IFilterProvider>().InstancePerRequest();
        builder.RegisterType<QuestionGroupProvider>().As<IQuestionGroupProvider>().InstancePerRequest();
        builder.RegisterType<StateProvider>().As<IStateProvider>().InstancePerRequest();
    }
}

Et j'ai ajouté un fournisseur comme paramètre pour mon constructeur d'API comme ceci:

// Readonly properties
private readonly ICategoryProvider _provider;

/// <summary>
/// Default constructor
/// </summary>
public CategoriesController(ICategoryProvider provider)
{
    _provider = provider;
}

Mais, lorsque j'essaie d'appeler l'API (en utilisant le facteur), j'obtiens cette erreur:

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

Je suis maintenant coincé, je ne vois pas du tout où se situe le problème. Le fournisseur de catégories a un constructeur comme celui-ci:

/// <summary>
/// Default constructor
/// </summary>
public CategoryProvider(IUnitOfWork unitOfWork, ICategoryService service)
{

    // Map our properties
    _unitOfWork = unitOfWork;
    _service = service;
}

Et le CategoryService a un constructeur comme celui-ci:

/// <summary>
/// The default constructor
/// </summary>
/// <param name="unitOfWork"></param>
public CategoryService(IUnitOfWork unitOfWork)
    : base(unitOfWork)
{
}

Et enfin, UnitOfWork a un constructeur comme celui-ci:

/// <summary>
/// Default constructor
/// </summary>
/// <param name="context">The database context</param>
public UnitOfWork(DbContext context)
{
    _context = context;
    _repositories = new Dictionary<Type, object>();
}

D'après ce que je peux dire, tout est configuré correctement. Quelqu'un peut-il repérer tout ce que j'ai oublié de faire?

3
r3plica 16 janv. 2017 à 20:17

2 réponses

Meilleure réponse

J'ai trouvé le problème, j'utilisais HttpConfiguration pour définir le résolveur de dépendances, cela aurait dû être GlobalConfiguration.Configuration.

Donc, quand j'ai changé ma ligne de:

config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

À

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

Tout a commencé à fonctionner.

6
r3plica 17 janv. 2017 à 10:30

Essayez d'enregistrer les assemblys qui ont été chargés dans le contexte d'exécution de votre domaine d'application juste avant de créer votre conteneur:

var assemblies = AppDomain.CurrentDomain.GetAssemblies(); builder.RegisterAssemblyModules(assemblies);

/// <summary>
/// Configures Autofac DI/IoC
/// </summary>
/// <param name="app"></param>
/// <param name="config"></param>
private IContainer ConfigureInversionOfControl(IAppBuilder app, HttpConfiguration config)
{

    // Create our container
    var builder = new ContainerBuilder();

    // You can register controllers all at once using assembly scanning...
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

    // Register our module
    builder.RegisterModule(new AutofacModule());

    // [!!!] ** Register assemblies of the current domain **
    var assemblies = AppDomain.CurrentDomain.GetAssemblies();
    builder.RegisterAssemblyModules(assemblies);

    // Build
    var container = builder.Build();

    // Lets Web API know it should locate services using the AutofacWebApiDependencyResolver
    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

    // Return our container
    return container;
}

Et n'oubliez pas d'avoir défini:

public class AutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {

      ...

      builder.RegisterControllers(typeof(WebApiApplication).Assembly);
      builder.RegisterApiControllers(typeof(WebApiApplication).Assembly);
    }
}
0
Felipe Cruz 16 janv. 2017 à 17:52