SQL Server CLR集成是否支持配置文件?

时间:2015-01-28 03:04:37

标签: c# sql-server configuration-files sqlclr configurationmanager

我使用SQL Server CLR集成来创建一个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>

但是当我执行PROCEDURE时,SQL Server显示错误System.NullReferenceException

SQL Server CLR集成是否支持App.config文件?

4 个答案:

答案 0 :(得分:12)

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

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

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

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>

请务必注意,如“使用应用程序配置...”链接中所述,对配置文件所做的更改不会立即可用。 HOWEVER 需要通过执行该文章中提到的方法之一(即DBCC FREESYSTEMCACHE)并重新启动SQL Server来强制重新加载。获取当前信息所需的全部内容是通过ConfigurationManager.RefreshSection(string sectionName)重新加载您正在使用的特定部分,如上例所示。 请参阅下面有关使用情况和效果的说明。

资源:


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


使用和表现

正如Joe B在comment below中所建议的那样,RefreshSection操作会有轻微的性能损失。如果包含刷新的代码每隔几分钟被调用一次以上,那么它就会产生明显的影响(由于配置文件的频率变化不足,这种影响是不必要的)。在这种情况下,您需要从频繁调用的代码中删除对RefreshSection的调用,并单独处理刷新。

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

另一种方法是卸载App Domain,该域将在下次引用该数据库中的任何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删除整个实例的所有缓存数据,这不仅仅影响SQLCLR。

关于LINUX上的SQL SERVER的更新

SQL Server现在,从2017版本开始,可在Linux上使用(woo hoo!)。但是,似乎从应用程序配置文件中读取在Linux上工作。我尝试了sqlservr.exe.[Cc]onfigsqlservr.[Cc]onfig之类的许多组合等等,并且没有任何工作要做。指定配置文件无法正常工作,因为需要EXTERNAL_ACCESS权限,并且Linux上只允许SAFE程序集(至少目前为止)。如果我找到一种方法让它工作,我会在这里发布详细信息。

答案 1 :(得分:3)

你显然会得到NullReferenceException,因为ConfigurationManager.AppSettings["connection"]返回null,然后你在null上调用ToString()。

在您发布问题之前,CLR Integration app.config上Google搜索的排名最高的网页是 Using an Application Configuration (app.config/web.config) File in SQL Server CLR Integration

Jonathan Kehayias的相关文章中,他陈述了

  

.NET中编程的一个常见部分是使用配置文件   将配置信息存储在易于修改的位置。   app.config或web.config文件在大多数情况下是非常有用的   .NET项目和开发人员可能需要维护此功能   作为数据库中对象与逻辑共享的一部分   申请也是如此。 问题是SQL CLR不允许使用   SQLCLR项目中的System.Configuration类

然后,他继续详细介绍了一个解决方法,其中涉及编辑项目文件以将新密钥注入到将app.config链接到项目的ItemGroup中。从那里你可以在你的代码中做一些basica争论,创建一个UserDefinedFunction来返回你需要的连接字符串或appSetting。

你最好阅读他在上述网址上发布的文章,因为它不是我的区域,我最后会公然剽窃他的内容,逐步提供如何操作。

答案 2 :(得分:0)

您是否尝试访问运行CLR的同一SQL Server?如果是这样,您可以使用一种特殊类型的连接字符串,称为&#34;上下文连接&#34;。

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

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

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

答案 3 :(得分:0)

这就是我的方法。对于我来说,它工作得非常好,我现在可以在任何实例上安装我的程序集,并且可以正常工作。

   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();
            }
        }