I am trying to call an external webservice in visual studio but I am getting the error.
System.Security.SecurityException: Request for the permission of type \'Syst
For network-related requests by themselves you would need to set your Assembly to PERMISSION_SET = EXTERNAL_ACCESS
. However, using System.Net.ServicePointManager.ServerCertificateValidationCallback
unfortunately requires PERMISSION_SET = UNSAFE
. If you do not expressly need to override the handling of SSL Certificates, then you should get rid of that delegate since it would be better for the Assembly to be set to EXTERNAL_ACCESS
.
Unfortunately, Visual Studio / SSDT (SQL Server Data Tools) does not make it very easy to take the appropriate steps needed to allow your Assembly to be set to either EXTERNAL_ACCESS
or UNSAFE
. They do, however, make it easy enough to set the TRUSTWORTHY
option to ON
, which is mostly a bad idea.
Please do not set TRUSTWORTHY ON
unless absolutely necessary! And it should only be "necessary" when loading an Assembly that you did not build and cannot re-sign. And that mostly happens when loading .NET Framework libraries that aren't "supported" and hence not already in SQL Server's CLR host. Outside of those circumstances, you should not be setting the database to TRUSTWORTHY ON
as it opens up a security hole.
Instead, it is much better to do the following:
USE [master];
CREATE ASYMMETRIC KEY [SomeKey]
AUTHORIZATION [dbo]
FROM EXECUTABLE FILE = 'C:\path\to\Some.dll';
CREATE LOGIN [SomeLogin]
FROM ASYMMETRIC KEY [SomeKey];
GRANT EXTERNAL ACCESS ASSEMBLY TO [SomeLogin]; -- or "UNSAFE" instead of "EXTERNAL ACCESS"
The above only needs to be done once per Instance, per key. So if you use the same snk
/ pfx
file for all of your assemblies, then the steps shown above only need to be done once per SQL Server Instance; the number of Assemblies and databases containing those Assemblies does not matter.
This approach allows you to keep better security on the database (by keeping TRUSTWORTHY
set to OFF
) and allows for more granular control of which assemblies are even allowed to be set to EXTERNAL_ACCESS
and/or UNSAFE
(since you can separate by using different keys for signing and Logins based on those different keys).
For a more detailed walk-through of the security options, please see the following article that I wrote on SQL Server Central: Stairway to SQLCLR Level 4: Security (EXTERNAL and UNSAFE Assemblies) (free registration is required).
Other notes:
Convert.ToString(uri)
. All of the Sql*
types have a .Value
property that returns the appropriate native type. So replace that with uri.Value
.DataAccess = DataAccessKind.Read
in the SqlFunction
attribute since you are not doing any data access. Setting DataAccess = DataAccessKind.Read
is a slight performance hit, so since you are not making use of it, just remove it.dataStream
and rdr
(being a Stream
and StreamReader
respectively) are "disposable" objects, so you really need to be calling .Dispose()
on them, which you can probably do instead of the .Close()
.Dispose
method being called on both of those objects, your process could hold open the external network handle, and that might not get released until the App Domain recycles which might not be for a long time. You need to either use the using
construct or properly structure a try
/ catch
/ finally
. This is rather dangerous code to be running within SQL Server without doing one of these two things.