Castle.Windsor实例化Dapper的错误版本SqlConnection

4
我们在使用Castle.Windsor实例化一个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.

这个异常的问题在于,.NET 4.5.1版本的System.Data中的SqlConnection类型不包含AccessToken属性,而.NET 4.6版本中有。换句话说,如果我试图手动实现...
var connection = new SqlConnection("connectionstring");
connection.AccessToken = "";

如果项目配置为.NET 4.5.1,则会出现构建错误,但在将AccessToken配置为.NET 4.6时会出现运行时错误。有任何想法是为什么Castle.Windsor会尝试创建v4.6 SqlConnection而不是.NET 4.5.1?解决/欺骗:我可以通过告诉Castle忽略该属性来避免这个问题,但这似乎是一个欺骗。这需要将其添加到注册中的PropertiesIgnore中。
container.Register(Component.For<IDbConnection>().ImplementedBy<SqlConnection>()
            .PropertiesIgnore(info => info.Name.Equals("AccessToken"))
            .LifestyleTransient()
            .DependsOn(Dependency.OnValue<string>          
             (ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString)));

一个非常明显的问题,你引用的是 System.Data 的哪个版本? - David Osborne
1个回答

3

所有.NET版本从4.5开始都是现场更新(如此在这里所示)

这意味着一旦安装了.NET 4.6,无论您如何实例化它,您都将始终获得SqlConnection的.NET 4.6版本。

在Visual Studio中构建应用程序时,您会针对.NET框架的特定版本进行构建,该版本通常位于以下文件夹中的某个位置: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework

这意味着在构建msbuild时,可以检查您是否正在使用目标框架版本中不可用的内容。

但是,当您运行64位应用程序时,它将使用通常位于C:\Windows\Microsoft.NET\Framework64\v4.0.30319中的程序集。

这是从.NET 4.0到.NET 4.6的所有版本均相同的文件夹,这就是现场升级的含义。

因此,当您在已安装.NET 4.6的开发环境上执行应用程序时,您将始终获得.NET 4.6版本(至少除非您采取特殊措施来加载其他版本的程序集)。

Castle Windsor将尝试使用公共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)));

为什么我没有想到那个注册方式呢!;) - Yngve B-Nilsen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接