SQL 服务器 CLR 集成是否支持配置文件?

Does SQL Server CLR Integration support configuration files?

我使用 SQL Server CLR Integration 创建一个 ASSEMBLY。

加载命令: CREATE ASSEMBLY TcpClr FROM 'G:\TcpClrTest.dll' WITH PERMISSION_SET = UNSAFE

没有App.Config

dll代码包含: string ip=ConfigurationManager.AppSettings["connection"].ToString();

另外 App.config 包含:

<appSettings> <add key="connection" value="127.0.0.1"/> </appSettings>

但是当我执行程序时,SQL 服务器显示错误 System.NullReferenceException

SQL 服务器 CLR 集成是否支持 App.config 文件?

您显然会得到一个 NullReferenceException,因为 ConfigurationManager.AppSettings["connection"] 是 returning null 然后您在一个 null 上调用 ToString()。

在您发布问题之前,CLR Integration app.config 上 Google 搜索排名最高的页面是这个 在 SQL Server CLR Integration.

中使用应用程序配置 (app.config/web.config) 文件

Jonathan Kehayias 的相关文章中,他说

A common part of programming in .NET is to use an configuration file to store configuration information in an easily modifiable location. The app.config or web.config file is an invaluable inclusion in most .NET projects and developers may need to maintain this functionality as a part of logic sharing between objects in the database and the application as well. The problem is that SQL CLR doesn't allow use of the System.Configuration class in SQLCLR projects.

然后他继续详细介绍了一种变通方法,其中涉及编辑项目文件以将新密钥注入将您的 app.config 链接到项目的 ItemGroup。从那里,您可以在代码中进行一些基本的争论,以创建一个 UserDefinedFunction 到 return 您需要的连接字符串或 appSetting。

你最好阅读他在上述 Url 上发表的文章,因为这不是我的领域,我最终会公然抄袭他的内容以提供逐步的操作方法。

您需要将 sqlservr.exe.config 文件放入实例根文件夹的 \Binn 文件夹中。例如:

C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn

如果您使用的是 SQL Server 2008 R2 (SP1) 或更新版本,您应该能够通过以下查询找到确切位置,该查询显示 [= 的完整路径101=]:

SELECT [filename] FROM sys.dm_server_services WHERE servicename LIKE N'SQL Server (%';

在您的代码中,顶部需要这一行:

using System.Configuration;

然后这将起作用:

[SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
public static SqlString GetConfig(SqlString WhichOne)
{
    ConfigurationManager.RefreshSection("connectionStrings");
    return ConfigurationManager.ConnectionStrings[WhichOne.Value].ToString();
}

sqlservr.exe.config 文件的内容:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <connectionStrings>
      <add name="Stuff" connectionString="Trusted_Connection=true; Enlist=false;" />
      <add name="ClrTest" connectionString="boo hoo" />
   </connectionStrings>
</configuration>

请务必注意,如 "Using an Application Configuration..." link 中所述,对配置文件所做的更改不会立即可用。 然而,您不需要通过执行该文章中提到的方法之一(即DBCC FREESYSTEMCACHE并重新启动来强制重新加载SQL 服务器)。如上例所示,获取当前信息所需要做的就是通过 ConfigurationManager.RefreshSection(string sectionName) 重新加载您正在使用的特定部分。 请参阅下面有关使用和性能的说明。

资源:


此外,除非绝对需要,否则不应将程序集创建为 UNSAFE。如果您只是想与其他机器建立 TCP 连接,那应该只需要 EXTERNAL_ACCESS.


用法和性能

正如 Joe B 在 中所建议的那样,RefreshSection 操作对性能有轻微影响。如果包含刷新的代码每隔几分钟被调用一次以上,那么它可能会产生明显的影响(考虑到配置文件更改的频率较低,这种影响是不必要的)。在这种情况下,您需要从频繁调用的代码中删除对 RefreshSection 的调用并独立处理刷新。

一种方法是让 SQLCLR 存储过程或标量函数只执行刷新而不执行其他操作。只要对配置文件进行了更改,就可以执行此操作。

另一种方法是卸载 App 域,这将在下次引用该数据库中的任何 SQLCLR 对象时重新加载配置文件。重新加载特定数据库(但不是整个实例)中所有应用程序域的一种相当简单的方法是将 TRUSTWORTHY 设置打开然后再次关闭,或者关闭然后再次打开,具体取决于当前状态那个设置。下面的代码将检查该设置的当前状态并相应地翻转它:

IF (EXISTS(
    SELECT  sd.*
    FROM    sys.databases sd
    WHERE   sd.[name] = DB_NAME() -- or N'name'
    AND     sd.[is_trustworthy_on] = 0
   ))
BEGIN
    PRINT 'Enabling then disabling TRUSTWORTHY...';
    ALTER DATABASE CURRENT SET TRUSTWORTHY ON;
    ALTER DATABASE CURRENT SET TRUSTWORTHY OFF;
END;
ELSE
BEGIN
    PRINT 'Disabling then enabling TRUSTWORTHY...';
    ALTER DATABASE CURRENT SET TRUSTWORTHY OFF;
    ALTER DATABASE CURRENT SET TRUSTWORTHY ON;
END;

不要使用任何更激烈的方法 -- DBCC FREESYSTEMCACHE、禁用然后启用 clr enabled 系统设置、重新启动实例等-- 因为几乎从来没有必要这样做。特别是重新启动实例,或者 DBCC FREESYSTEMCACHE 会丢弃整个实例的 all 缓存数据,这影响的不仅仅是 SQLCLR。

有关 SQL 服务器的更新 LINUX

SQL 服务器现已推出,从 2017 版开始,可在 Linux 上使用(哇哦!)。但是,从应用程序配置文件中读取似乎 在 Linux 上工作。我已经尝试了 sqlservr.exe.[Cc]onfigsqlservr.[Cc]onfig 等的许多组合,但没有任何效果。指定配置文件无法工作,因为这需要 EXTERNAL_ACCESS 权限,并且 Linux 上只允许 SAFE 程序集(至少现在是这样)。如果我找到让它工作的方法,我会 post 详细信息在这里。

您是否正在尝试访问与 CLR 运行 相同的 SQL 服务器?如果是这样,您可以使用一种特殊类型的连接字符串,称为 "context connection".

https://msdn.microsoft.com/en-us/library/ms131053.aspx

using(SqlConnection connection = new SqlConnection("context connection=true")) 
{
    connection.Open();
    // Use the connection
}

基本上,您告诉代码它应该使用底层 SQL 服务器(在该上下文中),您甚至不需要指定连接信息。如果您试图 运行 任意可重用代码作为 CLR,您可能犯下了某种软件犯罪行为,不应该这样做。

我就是这样做的。它对我来说工作得很好,我现在可以在任何实例上安装我的程序集,它会工作得很好。

   SqlConnectionStringBuilder sqlb = new SqlConnectionStringBuilder("");
        sqlb.ContextConnection = true;
        string newConnStr = sqlb.ToString();

        using (SqlConnection c = new SqlConnection(newConnStr))

        {
            c.Open();

            //This is the database name
            DatabaseName = c.Database;

            //We need to use some simple SQL to get the server and instance name.
            //Returned in the format of SERVERNAME\INSTANCENAME
            SqlCommand cmd = new SqlCommand("SELECT @@SERVERNAME [Server]", c);
            SqlDataReader rdr = cmd.ExecuteReader();
            if (rdr.Read())
            {
                ServerName = rdr["Server"].ToString();
            }
        }