Question

I'm trying to (learn) publish a SQLCLR function using Visual Studio 2017. (It's a simple function that sends an email.)

As a reference I used this articles on CodeProject and MSSQLTips:

Create, Run, Debug and Deploy SQL CLR Function with Visual Studio 2013 Database Project

Send Email from SQL Server Express Using a CLR Stored Procedure

On project properties->SQLCLR I've set:

Permission level : UNSAFE

And according to the article I've updated target databases:

sp_configure 'clr enabled', 1;  
GO  
RECONFIGURE;  
GO  

And after I've got the error I've followed this advice on MSSQLTips article:

If you get error messages when trying to compile the code you may need to alter the database using the following command and then try again to create the assembly and the stored procedure.

ALTER DATABASE msdb SET trustworthy ON

I've tried using two different target databases:

  • SQL-Server 2017 LocalDB
  • SQL-Server 2017 Express

I can build the project without errors, but when I publish the project I receive one error when it executes the next command:

CREATE ASSEMBLY [dbSysmac]
    AUTHORIZATION [dbo]
    FROM 0x5F8A900003000000...
    WITH PERMISSION_SET = UNSAFE;

(47,1): SQL72014: .Net SqlClient Data Provider: Msg 10327, Level 14, State 1, Line 1 CREATE ASSEMBLY for assembly 'dbSysmac' failed because assembly 'dbSysmac' is not trusted. The assembly is trusted when either of the following is true: the assembly is signed with a certificate or an asymmetric key that has a corresponding login with UNSAFE ASSEMBLY permission, or the assembly is trusted using sp_add_trusted_assembly.

What I'm doing wrong?

Was it helpful?

Solution

I've updated target databases:

 sp_configure 'clr enabled', 1;

Just to be clear, "clr enabled", and sp_configure in general, are instance-level, not database-level configuration.

I've followed this advice on MSSQLTips article

Yikes. Well, that article on MSSQLTips is more of a problem than the error that you are getting. It would be best if you forgot everything you saw in that article and never looked at it again. It is full of bad advice:

  1. SQLCLR not required for sending email in SQL Server Express (I have tested this and it does work). HOWEVER, it does not work in SQL Server Express LocalDB :-(
  2. You should use SqlString instead of String for input parameter types (and for return types)
  3. Deploying to msdb? Maybe it's just me, but I would never deploy code to msdb (and I would only add code to master if it is physically required, such as when marking a proc as either a start up proc or as a system proc).
  4. UNSAFE permission set? Why? For email? The assembly should be EXTERNAL_ACCESS. Code (assemblies, logins, users, or anything else) shouldn't be given more permissions than necessary.
  5. Setting TRUSTWORTHY ON for msdb is two problems in one:
    1. Setting TRUSTWORTHY ON is lazy. Sure, it's fine for doing proof-of-concepts / quick tests, but it is not a good long-term / production-level option. It's a huge security risk. Instead, Module Signing should be used. Here is a guide I wrote for how to accomplish this, and do so within Visual Studio:
      SQLCLR vs. SQL Server 2017, Part 2: "CLR strict security" - Solution 1
    2. TRUSTWORTHY is already ON for msdb. At least it is ON by default.
  6. The @body input parameter should be NVARCHAR(MAX), not NVARCHAR(4000). This is, after all, HTML email (i.e. myMessage.IsBodyHtml = True)
  7. No, absolutely do not store your plain-text email password in the .NET code. DLLs / Assemblies are not encrypted. ALL strings are stored as-is at the end of the EXE / DLL / Assembly. It takes almost no effort to display the contents of an assembly, and if you follow this advice, your SMTP server, login, and password will be stored for anyone to see. Either pass those in from a variable, or do a simple query to select from a table. You might even be able to get them from the Windows Registry.

What database are you actually publishing to? Assuming that you are publishing to another database that is not msdb, then you, at least simplistically, in this moment to move forward, need to set TRUSTWORTHY ON for the DB that you are publishing to. But again, enabling TRUSTWORTHY is just for testing (please see: PLEASE, Please, please Stop Using Impersonation, TRUSTWORTHY, and Cross-DB Ownership Chaining).

Now, if you are executing the ALTER DATABASE... manually and then still get the error upon publishing, then most likely you have the "deploy database properties" option selected (in Visual Studio: go to "Project Properties" | "Debug" tab | "Deployment Options" area towards the bottom). TRUSTWORTHY is one of those database properties. So, when "deploy database properties" is checked, then every deployment will set the options to match what is defined in the project. And by default, Trustworthy is not enabled.

Your options are:

  1. If you are deploying database properties:

    To enable Trustworthy in Visual Studio (for deployments): go to "Project Properties" | "Project Settings" tab | "Database Settings..." button | "Miscellaneous" tab. Check the box for "Trustworthy" and then click the "OK" button.

  2. If you are not deploying database properties:

    Enable trustworthy in the database where you are deploying the assembly (enabling TRUSTWORTHY in msdb won't help)

  3. Once you have this working correctly in development, handle security properly before pushing to production:

    SQLCLR vs. SQL Server 2017, Part 2: "CLR strict security" - Solution 1

For learning more about SQLCLR in general, please visit: SQLCLR Info. Be sure to check out the "Stairway to SQLCLR" link, which is a series I am writing on this topic on SQL Server Central.

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top