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
Vous devez vous connecter pour publier un commentaire.
À mon avis le seul point d'avoir des enregistrements dans le fichier config est de ne pas les avoir dans code et d'être en mesure de remplacer mise en œuvre sans recompilation. Afin de vous écrire en essayant de supprimer le code du formulaire. Ce que je ne comprends pas, c'est pourquoi vous voulez à la fois des enregistrements dans le fichier config en premier lieu. Retirez simplement le
Live
l'un de config pour les tests et laTest
de config pour l'application et enregistrer toutes les deux sans nom.Ainsi, par exemple, en application de l'app.config:
Depuis que vous avez vraiment sont les facteurs pour le faire à votre manière:
L'autre façon de contourner cela est d'inscrire dans le code seulement une façon de déterminer quelle instance est celui par défaut:
appSettings
l'article plutôt que de lecontainer
section. Par la présente, je voudrais commenter un enregistrement & décommentez les autres - juste un peu plus de travail.Pas beaucoup de travail. Sélectionnez
ctrl+e then c
de commenter et dectrl+e then u
décommenter avec seulement pointeur dans commentée de la partie. Et c'est une prévu l'utilisation de fichiers de configuration. Il est inutile ou même nuisible à avoir la même option de configuration en deux endroits.OriginalL'auteur Rafal