L'unité nommée cartographie problème

J'ai deux implémentations de IEmailService, l'un pour les tests et l'un pour le live (est-Un). Et j'ai un BusinessService qui a Un IEmailService de référence.

BusinessService
    IEmailService (has-A)

IEmailService
    TestEmailService (is-A)
    LiveEmailService (is-A)

Dans l'unité de config, j'ai d'enregistrer les deux IEmailService implémentations comme suit.

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
  <register type="DataAccess.IEmailService, DataAccess"
            mapTo="DataAccess.LiveEmailService, DataAccess"
            name="Live">
    <lifetime type="singleton" />
  </register>
  <register type="DataAccess.IEmailService, DataAccess"
            mapTo="DataAccess.TestEmailService, DataAccess"
            name="Test">
    <lifetime type="singleton" />
  </register>
<container>
</unity>

Basé sur la appSetting pour IEmailService je veux l'Unité de choisir la bonne mise en œuvre. Cela aidera lors des tests.

<appSettings>
    <add key="IEmailService" value="Test"/>
</appSettings>

Le problème est lorsque l'unité résout BusinessService, il tente de résoudre (none) nommé cartographie de IEmailService au lieu de Live ou Test et jette un ResolutionFailedException.

container.Resolve<BusinessService>(); jette ci-dessous exception:

BusinessServices.Test.BusinessServiceTest_Integration.Test103:

Microsoft.Practices.Unity.ResolutionFailedException : Resolution of the dependency failed, type = "BusinessServices.BusinessService", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, DataAccess.IEmailService, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was:

  Resolving BusinessServices.BusinessService,(none)
  Resolving parameter "emailService" of constructor BusinessServices.BusinessService(DataAccess.IEmailService emailService)
    Resolving DataAccess.IEmailService,(none)

  ----> System.InvalidOperationException : The current type, DataAccess.IEmailService, is an interface and cannot be constructed. Are you missing a type mapping?

La solution de contournement, je suis venu avec est de spécifier les enregistrements dans le code et avoir une méthode wrapper autour de container.RegisterType pour vous inscrire IEmailService avec (none) nommé cartographie et basé sur le appSetting valeur.

IUnityContainer container;

//registering unity
static void Load()
{
    container = new UnityContainer().LoadConfiguration();

    RegisterType<IEmailService, TestEmailService>("Test");
    RegisterType<IEmailService, LiveEmailService>("Live");
}

//register the `Test` or `Live` implementation with `(none)` named mapping as per appSetting
static void RegisterType<TFrom, TTo>(string name) 
    where TTo : TFrom
{
    var tFromAppSetting= ConfigurationManager.AppSettings[typeof(TFrom).Name];
    if (!string.IsNullOrEmpty(tFromAppSetting) && tFromAppSetting == name)
        container.RegisterType<TFrom, TTo>();
}

Cela fonctionne, mais je termine en précisant les inscriptions en deux endroits - config ainsi que le code. Est-il une meilleure façon de faire cela?

Mise à jour

J'avais eu corriger le code. Je n'ai pas besoin de l'unité de config. Le RegisterType<TFrom, TTo>(string name) registres soit la Test ou Live la mise en œuvre (none) nommé cartographie selon appSetting valeur. BusinessService est également résolu sans exception.

Comme il n'y a pas d'unité de config, je n'ai pas de charger la configuration.

container = new UnityContainer();

OriginalL'auteur hIpPy | 2012-11-07