web-dev-qa-db-fra.com

L'injection de dépendances ne fonctionne pas avec Web Api 2 et Autofac auto-hébergés par Owin

Je trouve mes pieds avec Web Api 2, Owin et Autofac et j'ai besoin de conseils, s'il vous plaît.

Présentation
J'ai une API Web auto-hébergée par Owin qui utilise Autofac pour l'IoC et l'injection de dépendances. Le projet est une application console agissant comme un service, ce qui signifie qu'elle peut être arrêtée et démarrée. J'ai un contrôleur d'authentification avec deux constructeurs: l'un sans paramètre et l'autre injecte un référentiel.

Problème
Lorsque j'exécute le service et appelle l'api, mon constructeur sans paramètre est appelé et mon référentiel n'est jamais injecté (_repository = null).

Recherche
J'ai fait pas mal de recherches et trouvé des projets utiles sur Github, que j'ai répliqués sur le tee mais il me manque une grande partie du puzzle. This a été utile mais n'a pas résolu mon problème. J'ai lu cette question sur Stack Overflow et Dane Sparza a eu un bon projet de démonstration mais je n'ai pas trouvé de solution claire. Le problème n'est pas l'auto-hébergement mais l'injection de dépendances.

Mon code (éclairci pour explication)

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();

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

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        config.Formatters.Remove(config.Formatters.XmlFormatter);

        var connectioninfo = ConnectionInfo.FromAppConfig("mongodb");

        var builder = new ContainerBuilder();                                    // Create the container builder.
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());         // Register the Web API controllers.
        builder.Register(c => new Logger()).As<ILogger>().InstancePerRequest();  // Register a logger service to be used by the controller and middleware.
        builder.RegisterType<AuthenticationRepository>().As<IAuthenticationRepository>().WithParameter(new NamedParameter("connectionInfo", connectioninfo)).InstancePerRequest();

        var container = builder.Build();

        var resolver = new AutofacWebApiDependencyResolver(container);           // Create an assign a dependency resolver for Web API to use.
        GlobalConfiguration.Configuration.DependencyResolver = resolver;         // Configure Web API with the dependency resolver

        app.UseCors(CorsOptions.AllowAll);  
        app.UseWebApi(config);
        app.UseAutofacWebApi(config);  // Make sure the Autofac lifetime scope is passed to Web API.
    }

Program.cs

 static void Main(string[] args)
    {           
        var service = new ApiService(typeof(Program), args);

        var baseAddress = "http://localhost:9000/";
        IDisposable _server = null;

        service.Run(
           delegate()
           {
               _server = WebApp.Start<Startup>(url: baseAddress);
           },
           delegate()
           {
               if (_server != null)
               {
                   _server.Dispose();
               }
           }
       );
    }

ApiController

public class AuthenticationController : ApiController
{
    private IAuthenticationRepository _repository;

    public AuthenticationController() { }

    public AuthenticationController(IAuthenticationRepository repository)
    {
        _repository = repository;
    }

    [AllowAnonymous]
    public IHttpActionResult Authenticate(string name, string password)
    {
        if (_repository == null)
            return BadRequest("User repository is null.");

        var valid = _repository.AuthenticateUser(name, password);
        return Ok(valid);
    }
}
25
ceebreenk

Vous devez utiliser le HttpConfiguration avec lequel vous amorcez OWIN partout. Donc ça:

GlobalConfiguration.Configuration.DependencyResolver = resolver;

Devraient devenir:

config.DependencyResolver = resolver;

A part ça, tout a l'air bien. Les contrôleurs Api sont enregistrés, bien que vous ne leur donniez pas de portée. Je ne sais pas si dans Autofac la portée par défaut est par demande pour les contrôleurs ou si elle a la notion de portée par demande (je sais que LightInject l'a).

En regardant autour de moi, je pense que vous avez suivi l'exemple du référentiel Google Code pour Autofac, qui utilise en effet GlobalConfiguration. Au lieu de cela, si vous regardez exemple GitHub , c'est un peu différent. Essayez d'effectuer les modifications en fonction de cela. Y compris ceci:

// This should be the first middleware added to the IAppBuilder.
app.UseAutofacMiddleware(container);

Mise à jour 2016

Ce que j'ai dit ci-dessus s'applique toujours, mais quelque chose en plus des documents d'Autofac (merci Brad):

Une erreur courante dans l'intégration OWIN est l'utilisation de GlobalConfiguration.Configuration. Dans OWIN, vous créez la configuration à partir de zéro. Vous ne devez faire référence à GlobalConfiguration.Configuration nulle part lorsque vous utilisez l'intégration OWIN.

38
Marcel N.