城堡.使用Dapper实例化错误版本的SqlConnection



我们在使用Castle时遇到了一个奇怪的问题。使用类型化工厂实例化SqlConnection:

注册如下:

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

IDbConnectionFactory:

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

现在,当我尝试使用以下代码访问新连接时:

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

我得到一个异常:

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.

这个Exception的问题是,在System。. net 4.5.1中的数据不包含属性AccessToken,而. net 4.6中的数据包含属性CC_3。换句话说,如果我尝试手动执行

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

如果项目配置为。net 4.5.1,我会得到一个构建错误,但如果配置为。net 4.6,则设置AccessToken时会出现运行时错误。

知道为什么吗,Castle。温莎试图创建一个v4.6 SqlConnection而不是。net 4.5.1?

解决方案/黑客

我可以通过告诉Castle忽略属性来解决这个问题,但这看起来像是一个hack。这样做需要我将其添加到注册中的PropertiesIgnore:

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

4.5之后的所有。net版本都进行了适当的更新如你所见

这意味着一旦你安装了。net 4.6,你将永远得到。net 4.6版本的SqlConnection,无论你如何实例化它。

当你在Visual Studio中构建你的应用程序时,你是在。net框架的一个特定版本上构建的,通常位于下面的文件夹中:C:Program Files (x86)Reference AssembliesMicrosoftFramework。NETFramework

这意味着当构建msbuild时,可以检查你没有使用在你的目标框架版本中不可用的东西。

但是,当您运行64位应用程序时,它将使用通常位于C:WindowsMicrosoft.NETFramework64v4.0.30319

的程序集。

这个文件夹适用于从。net 4.0到。net 4.6的所有版本,这就是就地升级的意思。

所以当你在安装了。net 4.6的开发环境中执行你的应用程序时,你总是会得到。net 4.6版本(至少除非你做一些特别的事情来加载其他版本的程序集)。

Castle Windsor将尝试使用public setter设置属性,它将使用反射来查找属性,这意味着它将在。net 4.6机器上找到。net 4.6属性,即使你是基于4.5.1构建的。

当它尝试设置AccessToken时失败的原因很可能是因为您的连接字符串与设置AccessToken不兼容。

如果您检查AccessToken setter的源代码,您将看到,如果您试图为不兼容的连接字符串设置它,即使您只尝试将AccessToken设置为空字符串,它也会抛出异常。

由于您不需要将任何依赖项注入到SqlConnection对象中,您也可以简单地使用new操作符创建它,然后您可以避免由于windsor试图注入连接的属性而引起的问题。使用这个注册应该可以工作:

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

最新更新