我使用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文件?
答案 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。
SQL Server现在,从2017版本开始,可在Linux上使用(woo hoo!)。但是,似乎从应用程序配置文件中读取不在Linux上工作。我尝试了sqlservr.exe.[Cc]onfig
和sqlservr.[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的相关文章中,他陈述了
然后,他继续详细介绍了一个解决方法,其中涉及编辑项目文件以将新密钥注入到将app.config链接到项目的ItemGroup中。从那里你可以在你的代码中做一些basica争论,创建一个UserDefinedFunction来返回你需要的连接字符串或appSetting。.NET中编程的一个常见部分是使用配置文件 将配置信息存储在易于修改的位置。 app.config或web.config文件在大多数情况下是非常有用的 .NET项目和开发人员可能需要维护此功能 作为数据库中对象与逻辑共享的一部分 申请也是如此。 问题是SQL CLR不允许使用 SQLCLR项目中的System.Configuration类。
你最好阅读他在上述网址上发布的文章,因为它不是我的区域,我最后会公然剽窃他的内容,逐步提供如何操作。
答案 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();
}
}