如何让DbProviderFactories.GetFactory()返回NuGet引入的Sqlite提供程序?
嘿Dave,我之前刚好处理过一模一样的场景,给你几个完全符合需求的方案,不用碰GAC或者machine.config,靠项目自身就能搞定:
方案1:通过项目配置文件注册(推荐给.NET Framework项目)
直接在你的app.config或者web.config里添加DbProviderFactories的注册节点,这样所有依赖GetFactory()的库都能自动识别到Sqlite提供程序。
添加的配置代码如下:
<configuration> <system.data> <DbProviderFactories> <!-- 先移除系统可能已存在的同名注册,避免冲突 --> <remove invariant="System.Data.SQLite" /> <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /> </DbProviderFactories> </system.data> </configuration>
如果你用的是微软官方推荐的
Microsoft.Data.Sqlite库(而非System.Data.SQLite),把上面的invariant和type换成下面的即可:<remove invariant="Microsoft.Data.Sqlite" /> <add name="Microsoft.Data.Sqlite" invariant="Microsoft.Data.Sqlite" description="Microsoft Data Provider for SQLite" type="Microsoft.Data.Sqlite.SqliteFactory, Microsoft.Data.Sqlite" />
这个方案的好处是一次配置全局生效,所有依赖DbProviderFactories的组件都能直接用,不需要修改任何业务代码。
方案2:代码动态注册(适合.NET Core/.NET 5+或不想改配置的场景)
如果不想修改配置文件,或者你的项目是.NET Core/.NET 5+(这类框架本身就不依赖machine.config),可以在应用启动的入口处(比如Program.Main或者Startup.cs的初始化方法里)添加一段代码,动态注册Sqlite提供程序:
using System.Data.Common; using System.Data.SQLite; // 如果是Microsoft.Data.Sqlite就换成using Microsoft.Data.Sqlite; // 先检查是否已经注册过,避免重复注册引发异常 if (!DbProviderFactories.GetFactoryClasses().Any(row => row.InvariantName == "System.Data.SQLite")) { DbProviderFactories.RegisterFactory("System.Data.SQLite", SQLiteFactory.Instance); }
对应
Microsoft.Data.Sqlite的版本:if (!DbProviderFactories.GetFactoryClasses().Any(row => row.InvariantName == "Microsoft.Data.Sqlite")) { DbProviderFactories.RegisterFactory("Microsoft.Data.Sqlite", Microsoft.Data.Sqlite.SqliteFactory.Instance); }
这段代码会在应用启动时把Sqlite的工厂实例注册到DbProviderFactories中,后续所有调用GetFactory("System.Data.SQLite")(或对应的Microsoft版本)的地方都会返回正确的Sqlite提供程序。
为什么这些方案可行?
不管用哪种方式,NuGet已经把Sqlite的程序包复制到了项目的输出目录,运行时CLR能直接找到这些dll,完全不需要放到GAC里。而且我们的注册都是在项目自身的配置或代码里完成的,完全不影响系统级的machine.config。
内容的提问来源于stack exchange,提问作者David Thielen

