Does SQL Server CLR Integration support configuration files?

一曲冷凌霜 提交于 2019-11-28 00:40:38

问题


I use SQL Server CLR Integration to create an ASSEMBLY.

Load Command: CREATE ASSEMBLY TcpClr FROM 'G:\TcpClrTest.dll' WITH PERMISSION_SET = UNSAFE

Without App.Config

The dll code contains : string ip=ConfigurationManager.AppSettings["connection"].ToString();

Also the App.config contains :

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

But when I execute the PROCEDURE,the SQL Server shows an error System.NullReferenceException

Does SQL Server CLR Integration support App.config files?


回答1:


You need to place a sqlservr.exe.config file in the \Binn folder of that instance's root folder. For example:

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

If you are using SQL Server 2008 R2 (SP1) or newer, you should be able to find the exact location via the following query, which shows the full path to sqlservr.exe:

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

In your code, you need this line at the top:

using System.Configuration;

And then this will work:

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

Contents of the sqlservr.exe.config file:

<?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>

It is important to note that, as stated in the "Using an Application Configuration..." link, changes made to the config file are not immediately available. HOWEVER, you do not need to force a reload by doing one of the methods mentioned in that article (i.e. DBCC FREESYSTEMCACHE, and restarting SQL Server). All that is required to get current information is to reload the particular section you are using via ConfigurationManager.RefreshSection(string sectionName) as shown in the example above. Please see note below regarding usage and performance.

Resources:

  • Using System.Configuration.dll in .NET sprocs and UDFs
  • Using an Application Configuration (app.config/web.config) File in SQL Server CLR Integration

Also, unless you absolutely need to, you shouldn't create your assembly as UNSAFE. If you are just trying to make TCP connections to other machines, that should only require EXTERNAL_ACCESS.


USAGE AND PERFORMANCE

As suggested by Joe B in a comment below, there is a slight performance hit for the RefreshSection operation. If the code containing the refresh is going to be called more than once every couple of minutes, then it can have a noticeable impact (an impact that is unnecessary given the lack of frequency of a config file changing). In this case, you will want to remove the call to RefreshSection from the code that is called frequently and handle the refresh independently.

One approach would be to have a SQLCLR Stored Procedure or Scalar Function that just does the refresh and nothing else. This can be executed whenever a change it made to the config file.

Another approach would be to unload the App Domain which will reload the config file upon the next time any SQLCLR object in that database is referenced. One fairly simple method to reload all App Domains in a particular Database (but not across the entire Instance) is to flip the TRUSTWORTHY setting On and then Off again, or Off and then On again, depending on the current state of that setting. The code below will check the current state of that setting and flip it accordingly:

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;

Please do not use any of the more drastic methods -- DBCC FREESYSTEMCACHE, disabling then enabling the clr enabled system setting, restarting the Instance, etc -- as it is almost never necessary to do so. Especially restarting the Instance, or DBCC FREESYSTEMCACHE which drops all cached data for the entire Instance, which affects much more than just SQLCLR.

UPDATE REGARDING SQL SERVER ON LINUX

SQL Server is now, starting with version 2017, available on Linux (woo hoo!). However, it seems that reading from the app config file does not work on Linux. I have tried many combinations of sqlservr.exe.[Cc]onfig and sqlservr.[Cc]onfig, etc, and the like and have not gotten anything to work. Specifying a config file can't work as that requires EXTERNAL_ACCESS permission and only SAFE Assemblies are allowed on Linux (as of right now, at least). If I find a way to get it working I will post the details here.




回答2:


You'll obviously be getting a NullReferenceException because ConfigurationManager.AppSettings["connection"] is returning null and then you are calling ToString() on a null.

Until you posted your question the top ranking page for a Google search on CLR Integration app.config was this Using an Application Configuration (app.config/web.config) File in SQL Server CLR Integration.

In the associated article by Jonathan Kehayias, he states

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.

He then goes on to detail a workaround which involves editing the project file to inject a new key into an ItemGroup that links your app.config to the project. From there you can do some basica wrangling from within your code to create a UserDefinedFunction to return the connection string or appSetting you require.

You are best to read the article posted by him at the aforementioned Url as it's not my area and I would just end up blatantly plagiarizing his content to provide a step by step of how to do.




回答3:


Are you trying to access the same SQL Server that the CLR is running on? If so, you can use a special type of connection string called a "context connection".

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

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

Basically you tell the code that it should use the underlying SQL Server (in that context) and you won't even need to specify connection info. If you're trying to run arbitrary reusable code as a CLR, you're probably committing some sort of software crime and should just not do that.




回答4:


This is how I did it. It's working perfectly for me, and I can install my assembly on any instance now and it will work perfectly.

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


来源:https://stackoverflow.com/questions/28183917/does-sql-server-clr-integration-support-configuration-files

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!