Search code examples
c#unity-container

Unity and dependency with constructor params


I have an issue on Unity when I try to use a class with interface, that have an implementation with 4 parameters.

Here the error stack trace :

Resolution of the dependency failed, type = "Keolis.ODM.Controllers.TypeTacheApiController", name = "(none)".
↵Exception occurred while: while resolving.
↵Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.
↵-----------------------------------------------
↵At the time of the exception, the container was:
↵
↵  Resolving Keolis.ODM.Controllers.TypeTacheApiController,(none)
↵  Resolving parameter "typeTacheService" of constructor Keolis.ODM.Controllers.TypeTacheApiController(Keolis.ODM.Business.ITypeTacheService typeTacheService)
↵    Resolving Keolis.ODM.Business.TypeTacheService,(none) (mapped from Keolis.ODM.Business.ITypeTacheService, (none))
↵    Resolving parameter "mediation" of constructor Keolis.ODM.Business.TypeTacheService(Keolis.Mediation.IMediation mediation, Keolis.ODM.Models.Repositories.ITypeTacheRepository typeTacheRepository, Keolis.Okapi.Models.Repositories.ITypeTacheRepository typeTacheOkapiRepository)
↵      Resolving Keolis.Mediation.WebService.Mediation,(none) (mapped from Keolis.Mediation.IMediation, (none))
↵      Resolving parameter "profilOkapiRepository" of constructor Keolis.Mediation.WebService.Mediation(Keolis.Okapi.Models.Repositories.IProfilOkapiRepository profilOkapiRepository, Keolis.Okapi.Models.Repositories.ISocieteOkapiRepository societeOkapiRepository, Keolis.Okapi.Models.Repositories.ICentreOkapiRepository centreOkapiRepository, Keolis.Okapi.Models.Repositories.IUtilisateurOkapiRepository utilisateurOkapiRepository)
↵        Resolving Keolis.Okapi.Models.Repositories.ProfilOkapiRepository,(none) (mapped from Keolis.Okapi.Models.Repositories.IProfilOkapiRepository, (none))
↵        Resolving parameter "serveur" of constructor Keolis.Okapi.Models.Repositories.ProfilOkapiRepository(System.String serveur, System.String catalog, System.String user, System.String pass)
↵          Resolving System.String,(none)
↵"

And the UnityConfig

    public static void RegisterTypes(IUnityContainer container)
    {
        // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
        container.LoadConfiguration();

        var repository = container.Resolve<ILocalDatabaseService>();
        var referentielLocalDatabase = repository.GetRsh();

        container.RegisterType<Okapi.Models.Repositories.ITypeHeureRepository, Okapi.Models.Repositories.TypeHeureRepository>();
        container.Resolve<Okapi.Models.Repositories.ITypeHeureRepository>(new ResolverOverride[] {
            new ParameterOverride("serveur", referentielLocalDatabase.Serveur),
            new ParameterOverride("catalog", referentielLocalDatabase.Base),
            new ParameterOverride("user", referentielLocalDatabase.User),
            new ParameterOverride("pass", referentielLocalDatabase.Password)
            });

        container.RegisterType<Okapi.Models.Repositories.ITypeTacheRepository, Okapi.Models.Repositories.TypeTacheRepository>();
        container.Resolve<Okapi.Models.Repositories.ITypeTacheRepository>(new ResolverOverride[] {
            new ParameterOverride("serveur", referentielLocalDatabase.Serveur),
            new ParameterOverride("catalog", referentielLocalDatabase.Base),
            new ParameterOverride("user", referentielLocalDatabase.User),
            new ParameterOverride("pass", referentielLocalDatabase.Password)
            });

        container.RegisterType<Okapi.Models.Repositories.IUtilisateurOkapiRepository, Okapi.Models.Repositories.UtilisateurOkapiRepository>();
        var utilisateur = container.Resolve<Okapi.Models.Repositories.IUtilisateurOkapiRepository>(new ResolverOverride[] {
            new ParameterOverride("serveur", referentielLocalDatabase.Serveur),
            new ParameterOverride("catalog", referentielLocalDatabase.Base),
            new ParameterOverride("user", referentielLocalDatabase.User),
            new ParameterOverride("pass", referentielLocalDatabase.Password)
            });

        container.RegisterType<Okapi.Models.Repositories.ISocieteOkapiRepository, Okapi.Models.Repositories.SocieteOkapiRepository>();
        var societe = container.Resolve<Okapi.Models.Repositories.ISocieteOkapiRepository>(new ResolverOverride[] {
            new ParameterOverride("serveur", referentielLocalDatabase.Serveur),
            new ParameterOverride("catalog", referentielLocalDatabase.Base),
            new ParameterOverride("user", referentielLocalDatabase.User),
            new ParameterOverride("pass", referentielLocalDatabase.Password)
            });

        container.RegisterType<Okapi.Models.Repositories.IProfilOkapiRepository, Okapi.Models.Repositories.ProfilOkapiRepository>();
        var profil = container.Resolve<Okapi.Models.Repositories.IProfilOkapiRepository>(new ResolverOverride[] {
            new ParameterOverride("serveur", referentielLocalDatabase.Serveur),
            new ParameterOverride("catalog", referentielLocalDatabase.Base),
            new ParameterOverride("user", referentielLocalDatabase.User),
            new ParameterOverride("pass", referentielLocalDatabase.Password)
            });

        container.RegisterType<Okapi.Models.Repositories.ICentreOkapiRepository, Okapi.Models.Repositories.CentreOkapiRepository>();
        var centre = container.Resolve<Okapi.Models.Repositories.ICentreOkapiRepository>(new ResolverOverride[] {
            new ParameterOverride("serveur", referentielLocalDatabase.Serveur),
            new ParameterOverride("catalog", referentielLocalDatabase.Base),
            new ParameterOverride("user", referentielLocalDatabase.User),
            new ParameterOverride("pass", referentielLocalDatabase.Password)
            });

        container.RegisterType<Okapi.Models.Repositories.IBuildVersionOkapiRepository, Okapi.Models.Repositories.BuildVersionOkapiRepository>();
        container.Resolve<Okapi.Models.Repositories.IBuildVersionOkapiRepository>(new ResolverOverride[] {
            new ParameterOverride("serveur", referentielLocalDatabase.Serveur),
            new ParameterOverride("catalog", referentielLocalDatabase.Base),
            new ParameterOverride("user", referentielLocalDatabase.User),
            new ParameterOverride("pass", referentielLocalDatabase.Password)
            });

        container.RegisterType<Keolis.Mediation.IMediation, Keolis.Mediation.WebService.Mediation>(new InjectionConstructor(
            new Okapi.Models.Repositories.ProfilOkapiRepository(referentielLocalDatabase.Serveur, referentielLocalDatabase.Base, referentielLocalDatabase.User, referentielLocalDatabase.Password),
            new Okapi.Models.Repositories.SocieteOkapiRepository(referentielLocalDatabase.Serveur, referentielLocalDatabase.Base, referentielLocalDatabase.User, referentielLocalDatabase.Password),
            new Okapi.Models.Repositories.CentreOkapiRepository(referentielLocalDatabase.Serveur, referentielLocalDatabase.Base, referentielLocalDatabase.User, referentielLocalDatabase.Password),
            new Okapi.Models.Repositories.UtilisateurOkapiRepository(referentielLocalDatabase.Serveur, referentielLocalDatabase.Base, referentielLocalDatabase.User, referentielLocalDatabase.Password)
            ));

        //container.RegisterType<Keolis.Mediation.IMediation, Keolis.Mediation.WebService.Mediation>(new InjectionConstructor(
        //    profil, societe, centre, utilisateur));

        //container.Resolve<Keolis.Mediation.IMediation>(new ResolverOverride[] {
        //    new ParameterOverride("profilOkapiRepository", profil),
        //    new ParameterOverride("societeOkapiRepository", societe),
        //    new ParameterOverride("centreOkapiRepository", centre),
        //    new ParameterOverride("utilisateurOkapiRepository", utilisateur)
        //});
    }

And the implementation of IMediation

 public Mediation(IProfilOkapiRepository profilOkapiRepository,
        ISocieteOkapiRepository societeOkapiRepository,
        ICentreOkapiRepository centreOkapiRepository,
        IUtilisateurOkapiRepository utilisateurOkapiRepository)
    {
        _profilOkapiRepository = profilOkapiRepository;
        _societeOkapiRepository = societeOkapiRepository;
        _centreOkapiRepository = centreOkapiRepository;
        _utilisateurOkapiRepository = utilisateurOkapiRepository;
        _deser = new Deserializer();
    }

I have tried several config, code behind and web.config, but ever the same errors on last resolve (Mediation).

So, how to register a class that have interface with parameters ?

Thanks for your help.

EDIT : Working code

public static void RegisterTypes(IUnityContainer container)
{
    // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
    container.LoadConfiguration();

    var repository = container.Resolve<ILocalDatabaseService>();
    var referentielLocalDatabase = repository.GetRsh();

    // This says "if you ever need need a string called 'xxxx', get that one."
    container.RegisterInstance<string>("serveur", referentielLocalDatabase.Serveur);
    container.RegisterInstance<string>("catalog", referentielLocalDatabase.Base);
    container.RegisterInstance<string>("user", referentielLocalDatabase.User);
    container.RegisterInstance<string>("pass", referentielLocalDatabase.Password);

    // Here it says "Find a constructor that needs 4 strings, and use
    // these registered string.
    container.RegisterType<Okapi.Models.Repositories.ITypeHeureRepository, Okapi.Models.Repositories.TypeHeureRepository>(
        new InjectionConstructor(
            new ResolvedParameter<string>("serveur"),
            new ResolvedParameter<string>("catalog"),
            new ResolvedParameter<string>("user"),
            new ResolvedParameter<string>("pass"))
        );

    container.RegisterType<Okapi.Models.Repositories.ITypeTacheRepository, Okapi.Models.Repositories.TypeTacheRepository>(
        new InjectionConstructor(
            new ResolvedParameter<string>("serveur"),
            new ResolvedParameter<string>("catalog"),
            new ResolvedParameter<string>("user"),
            new ResolvedParameter<string>("pass"))
        );

    container.RegisterType<Okapi.Models.Repositories.IUtilisateurOkapiRepository, Okapi.Models.Repositories.UtilisateurOkapiRepository>(
        new InjectionConstructor(
            new ResolvedParameter<string>("serveur"),
            new ResolvedParameter<string>("catalog"),
            new ResolvedParameter<string>("user"),
            new ResolvedParameter<string>("pass"))
        );

    container.RegisterType<Okapi.Models.Repositories.ISocieteOkapiRepository, Okapi.Models.Repositories.SocieteOkapiRepository>(
        new InjectionConstructor(
            new ResolvedParameter<string>("serveur"),
            new ResolvedParameter<string>("catalog"),
            new ResolvedParameter<string>("user"),
            new ResolvedParameter<string>("pass"))
        );

    container.RegisterType<Okapi.Models.Repositories.IProfilOkapiRepository, Okapi.Models.Repositories.ProfilOkapiRepository>(
        new InjectionConstructor(
            new ResolvedParameter<string>("serveur"),
            new ResolvedParameter<string>("catalog"),
            new ResolvedParameter<string>("user"),
            new ResolvedParameter<string>("pass"))
        );

    container.RegisterType<Okapi.Models.Repositories.ICentreOkapiRepository, Okapi.Models.Repositories.CentreOkapiRepository>(
        new InjectionConstructor(
            new ResolvedParameter<string>("serveur"),
            new ResolvedParameter<string>("catalog"),
            new ResolvedParameter<string>("user"),
            new ResolvedParameter<string>("pass"))
        );

    container.RegisterType<Okapi.Models.Repositories.IBuildVersionOkapiRepository, Okapi.Models.Repositories.BuildVersionOkapiRepository>(
        new InjectionConstructor(
            new ResolvedParameter<string>("serveur"),
            new ResolvedParameter<string>("catalog"),
            new ResolvedParameter<string>("user"),
            new ResolvedParameter<string>("pass"))
        );

    // Here it says "For IMediation, use the Mediation class".
    // The constructor you've shown us will required the other interfaces and
    // the container will be like "I know how to create a class of all of
    // these interfaces. I'll do that!"
    container.RegisterType<Mediation.IMediation, Mediation.WebService.Mediation>();            
}

Solution

  • You're kinda (euphemism) using Unity wrong. When you do the registration, you should almost always do registrations only, not register/resolve/"use the product to register" etc. You want to defer the resolution, and the class instantiation, to the latest responsible moment.

    Also, using ParameterOverride should be used to override parameters you'd have set for a specific case, when the ones you registered do not work. In your case, you could register them. Here's how I'd do it:

    (I removed the "Okapi.Models." and "Keolis.Mediation." everywhere for readability.)

    public static void RegisterTypes(IUnityContainer container)
    {
        var repository = container.Resolve<ILocalDatabaseService>();
        var referentielLocalDatabase = repository.GetRsh();
    
        // This says "if you ever need need a string called 'xxxx', get that one."
        container.RegisterInstance<string>("serveur", referentielLocalDatabase.Serveur);
        container.RegisterInstance<string>("catalog", referentielLocalDatabase.Base);
        container.RegisterInstance<string>("user", referentielLocalDatabase.User);
        container.RegisterInstance<string>("pass", referentielLocalDatabase.Password);
    
        // Here it says "Find a constructor that needs 4 strings, and use
        // these registered string.
        container.RegisterType<Repositories.ITypeHeureRepository, Repositories.TypeHeureRepository>(
            new ParameterResolve<string>("serveur"),
            new ParameterResolve<string>("catalog"),
            new ParameterResolve<string>("user"),
            new ParameterResolve<string>("pass"));
    
        container.RegisterType<Repositories.ITypeTacheRepository, Repositories.TypeTacheRepository>(
            new ParameterResolve<string>("serveur"),
            new ParameterResolve<string>("catalog"),
            new ParameterResolve<string>("user"),
            new ParameterResolve<string>("pass"));
    
        container.RegisterType<Repositories.IUtilisateurOkapiRepository, Repositories.UtilisateurOkapiRepository>(
            new ParameterResolve<string>("serveur"),
            new ParameterResolve<string>("catalog"),
            new ParameterResolve<string>("user"),
            new ParameterResolve<string>("pass"));
    
        container.RegisterType<Repositories.ISocieteOkapiRepository, Repositories.SocieteOkapiRepository>(
            new ParameterResolve<string>("serveur"),
            new ParameterResolve<string>("catalog"),
            new ParameterResolve<string>("user"),
            new ParameterResolve<string>("pass"));
    
        container.RegisterType<Repositories.IProfilOkapiRepository, Repositories.ProfilOkapiRepository>(
            new ParameterResolve<string>("serveur"),
            new ParameterResolve<string>("catalog"),
            new ParameterResolve<string>("user"),
            new ParameterResolve<string>("pass"));
    
        container.RegisterType<Repositories.ICentreOkapiRepository, Repositories.CentreOkapiRepository>(
            new ParameterResolve<string>("serveur"),
            new ParameterResolve<string>("catalog"),
            new ParameterResolve<string>("user"),
            new ParameterResolve<string>("pass"));
    
        container.RegisterType<Repositories.IBuildVersionOkapiRepository, Repositories.BuildVersionOkapiRepository>(
            new ParameterResolve<string>("serveur"),
            new ParameterResolve<string>("catalog"),
            new ParameterResolve<string>("user"),
            new ParameterResolve<string>("pass"));
    
        // Here it says "For IMediation, use the Mediation class".
        // The constructor you've shown us will required the other interfaces and
        // the container will be like "I know how to create a class of all of
        // these interfaces. I'll do that!"
        container.RegisterType<IMediation, WebService.Mediation>();
    }
    

    Haven't tested the code because it has too many dependencies, but it should work.