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

我使用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还包含:

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

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

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

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文件的内容:

        

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

资源:

  • 在.NET sprocs和UDF中使用System.Configuration.dll
  • 在SQL Server CLR集成中使用应用程序配置(app.config / web.config)文件

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


用途和表现

正如Joe B在下面的评论中所建议的那样 , RefreshSection操作会有轻微的性能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的更新

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

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

在您发布问题之前,在CLR Integration app.config上进行Google搜索的排名最高的页面就是在SQL Server CLR集成中使用应用程序配置(app.config / web.config)文件 。

在Jonathan Kehayias的相关文章中,他说

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

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

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

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

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运行,那么您可能犯了某种软件犯罪,而且不应该这样做。

这就是我做到的。 它对我来说非常合适,我现在可以在任何实例上安装我的程序集,它可以完美地运行。

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