I have created a .Net assembly and imported it into SQL Server and use it in a scalar-valued function (SVF).
When I execute the SVF it works fine. The second time also. But every third time the SVF fails and the underlying error is
System.NullReferenceException: Object reference not set to an instance of an object
I have added try/catch statements and debug data to the CLR, but I still have no clue as to why this CLR fails.
Can you help me out?
This is the C# code:
[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)]
public static SqlString HEAD(SqlString Uri)
{
string statusCode = "";
// Debug info
string debugData = "1,";
try
{
debugData += "2,";
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
debugData += "3,";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(Convert.ToString(Uri));
req.Method = "HEAD";
req.AllowAutoRedirect = true;
debugData += "4,";
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
debugData += "5,";
if (resp.StatusCode == HttpStatusCode.MethodNotAllowed)
{
// Use GET instead of HEAD
debugData += "6,";
req = (HttpWebRequest)WebRequest.Create(Convert.ToString(Uri));
req.Method = "GET";
resp = (HttpWebResponse)req.GetResponse();
}
debugData += "7,";
statusCode = ((int)resp.StatusCode).ToString();
debugData += "8,";
}
catch (WebException ex)
{
debugData += "9,";
HttpWebResponse webResponse = (HttpWebResponse)ex.Response;
debugData += "10,";
statusCode = ((int)webResponse.StatusCode).ToString();
debugData += "11,";
}
catch (Exception ex)
{
debugData += "12,";
statusCode = debugData + ex.Message;
debugData += "13,";
}
debugData += "14,";
//return (statusCode);
return debugData;
}
The method takes a string as input (which is a URL) and checks if the URL actually exists by doing a HttpWebrequest with a HEAD method.
It returns the status code, or an error message (hence the string as output).
The assembly has been successfully imported into my database:
ALTER DATABASE MyDatabase SET TRUSTWORTHY ON;
GO
CREATE ASSEMBLY SQLHttpRequest
FROM N'C:\somefolder\SQLHttpRequest.dll'
WITH PERMISSION_SET=UNSAFE;
GO
And this is the SVF:
CREATE FUNCTION dbo.uf_head_webrequest
(@Uri nvarchar(max))
RETURNS nvarchar(max)
AS
EXTERNAL NAME SQLHttpRequest.[SQLHttpRequest.HTTPFunctions].HEAD;
This is how I test this function:
declare @uri nvarchar(1000) = 'https://logos-download.com/wp-content/uploads/2016/02/Microsoft_logo_SQL-700x566.png'
SELECT dbo.uf_head_webrequest(@uri)
The output is 1,2,3,4,5,7,8,14,
However, if I execute it a couple of times, I get this response:
Msg 6522, Level 16, State 1, Line 2
A .NET Framework error occurred during the execution of user-defined routine or aggregate "uf_head_webrequest":
System.NullReferenceException: Object reference not set to an instance of an object.
System.NullReferenceException:
at SQLHttpRequest.HTTPFunctions.HEAD(SqlString Uri)
.
I understand the concept of object instantiation but don't understand why I don't get any debug data back.
I have searched the internet and came up with this question on SO:
SQLCLR .NET Error: Object reference not set to an instance of an object
This describes problems with NULL values. But in my opinion, this is not the case here. Especially because I am using the same Uri again and again.
Thanks!
nullvariable. This has nothing to do with SQLCLR. Using blocking operations like this in a database is a good way to cause lots of blocking too. It's far easier and more efficient to perform HTTP calls from client codeex.Responsecan benull, asWebExceptionwon't have a response if there was no response (for example a connectivity issue). I agree with everyone else in this thread, web requests from SQL sounds like a bad idea.