Castle.Windsor instancier une mauvaise version de SqlConnection avec Dapper

.net-4.5 .net-4.6 c# castle-windsor dapper

Question

Nous avons un problème étrange lorsque vous utilisez Castle.Windsor pour instancier une SqlConnection en utilisant une fabrique typée:

L'enregistrement ressemble à ceci:

container.Register(Component.For<IDbConnectionFactory>().AsFactory().LifestyleTransient());

container.Register(Component.For<IDbConnection>().ImplementedBy<SqlConnection>()
            .LifestyleTransient()
            .DependsOn(Dependency.OnValue<string>
            (ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString)));

Et l' IDbConnectionFactory :

public interface IDbConnectionFactory
{
    IDbConnection Create();
    void Release();
}

Maintenant, quand j'essaie d'accéder à une nouvelle connexion en utilisant ce code:

using (var connection = _connectionFactory.Create())
{

}

Je reçois une exception:

An unhandled exception of type 
'Castle.MicroKernel.ComponentActivator.ComponentActivatorException' occurred 
in Castle.Windsor.dll

Additional information: Error setting property SqlConnection.AccessToken in component 
System.Data.SqlClient.SqlConnection. See inner exception for more information.

If you don't want Windsor to set this property you can do it by either decorating it 
with DoNotWireAttribute or via registration API.

Alternatively consider making the setter non-public.

Le problème avec cette exception est que le type SqlConnection dans System.Data pour .NET 4.5.1 ne contient pas la propriété AccessToken contrairement à celle de .NET 4.6. En d'autres termes, si j'essaie de faire manuellement

var connection = new SqlConnection("connectionstring");
connection.AccessToken = "";

Je reçois une erreur de génération si le projet est configuré pour .NET 4.5.1, mais une erreur d'exécution lors de la configuration d'AccessToken s'il est configuré pour .NET 4.6.

Toute idée de la raison pour laquelle Castle.Windsor tente de créer un SqlConnection v4.6 au lieu d'un .NET 4.5.1?

Solution de contournement / piratage

Je peux contourner le problème en disant à Castle d'ignorer la propriété, mais cela semble être un piratage. Pour ce faire, je dois l’ajouter à PropertiesIgnore dans l’enregistrement:

container.Register(Component.For<IDbConnection>().ImplementedBy<SqlConnection>()
            .PropertiesIgnore(info => info.Name.Equals("AccessToken"))
            .LifestyleTransient()
            .DependsOn(Dependency.OnValue<string>          
             (ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString)));

Réponse acceptée

Toutes les versions de .NET depuis 4.5 sont mises à jour comme vous pouvez le voir ici .

Cela signifie qu'une fois que vous avez installé .NET 4.6, vous obtenez toujours la version .NET 4.6 de SqlConnection, quelle que soit la manière dont vous l'instanciez.

Lors de la création de votre application dans Visual Studio, vous générez sur une version spécifique du framework .NET généralement située dans un dossier sous: C: \ Program Files (x86) \ Reference Assemblies \ Microsoft \ Framework.NETFramework

Cela signifie que lors de la création de msbuild, vous pouvez vérifier que vous n'utilisez pas quelque chose qui n'est pas disponible dans la version du framework que vous ciblez.

Cependant, lorsque vous exécuterez votre application 64 bits, elle utilisera les assemblages généralement situés dans C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319.

C'est le même dossier pour toutes les versions de .NET 4.0 à .NET 4.6, c'est ce que signifie la mise à niveau.

Donc, lorsque vous exécutez votre application sur votre environnement de développement sur lequel .NET 4.6 est installé, vous obtiendrez toujours la version .NET 4.6 (du moins à moins que vous ne fassiez quelque chose de spécial pour charger d'autres versions des assemblys).

Castle Windsor essaiera de définir des propriétés avec le setter public et utilisera la réflexion pour trouver les propriétés, ce qui signifie qu'il trouvera les propriétés .NET 4.6 sur une machine .NET 4.6, même si vous construisez sur la version 4.5.1.

La raison pour laquelle il échoue lorsqu'il essaie de définir AccessToken est probablement la raison pour laquelle votre chaîne de connexion n'est pas compatible avec la définition d'AccessToken.

Si vous vérifiez le code source du programme de réglage AccessToken, vous verrez qu'il générera une exception si vous tentez de définir une chaîne de connexion incompatible, même si vous essayez uniquement de définir AccessToken sur la chaîne vide.

Comme vous n'avez pas besoin d'injecter des dépendances dans l'objet SqlConnection, vous pouvez aussi bien le créer en utilisant le nouvel opérateur, puis vous éviterez le problème causé par les tentatives de Windsors d'injecter les propriétés de la connexion. Utiliser cet enregistrement devrait fonctionner:

container.Register(Component.For<IDbConnection>().ImplementedBy<SqlConnection>()
        .LifestyleTransient()
        .UsingFactoryMethod(() => new SqlConnection          
       (ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString)));


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi