In order to make network request from sql clr code the assembly must be configured with EXTERNAL_ACCESS
permission. You can set the specified permission by using CREATE ASSEMBLY statement
CLR User-Defined function security exception
Question
I have created a CLR User-defined function to look up the latitude and longitude information of a location using Google geocode. The function is as follows:
using System;
using System.Net;
using System.Xml.XPath;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public partial class latlong
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString GetLatLong(string address, string city, string state, string zip)
{
string latitude = "#NA", longitude = "#NA";
string url = "http://maps.googleapis.com/maps/api/geocode/xml?address=";
string[] addresssplit = Regex.Split(address, @"\W+");
if (address != "NULL")
for (int i = 0; i < addresssplit.Length; i++)
url = url + addresssplit[i] + "+";
if (city != "NULL")
{
if (state != "NULL")
{
if (zip != "NULL") url = url + city + "+" + state + "+" + zip;
else url = url + city + "+" + state;
}
else
{
if (zip!= "NULL") url = url + city + "+" + zip;
else url = url + city;
}
}
else
{
if (state != "NULL")
{
if (zip != "NULL") url = url + state + "+" + zip;
else url = url + state;
}
else
{
if (zip != "NULL") url = url + zip;
}
}
url = url + "&sensor=false";
WebResponse response = null;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
response = request.GetResponse();
if (response != null)
{
XPathDocument document = new XPathDocument(response.GetResponseStream());
XPathNavigator navigator = document.CreateNavigator();
XPathNodeIterator statusIterator = navigator.Select("/GeocodeResponse/status");
while (statusIterator.MoveNext())
if (statusIterator.Current.Value != "OK")
{
Thread.Sleep(1000);
return new SqlString("OQL, OQL");
}
XPathNodeIterator resultIterator = navigator.Select("/GeocodeResponse/result");
while (resultIterator.MoveNext())
{
XPathNodeIterator geometryIterator = resultIterator.Current.Select("geometry");
while (geometryIterator.MoveNext())
{
XPathNodeIterator locationIterator = geometryIterator.Current.Select("location");
while (locationIterator.MoveNext())
{
XPathNodeIterator latIterator = locationIterator.Current.Select("lat");
while (latIterator.MoveNext())
latitude = latIterator.Current.Value;
XPathNodeIterator longIterator = locationIterator.Current.Select("long");
while (longIterator.MoveNext())
longitude = longIterator.Current.Value;
}
}
}
}
Thread.Sleep(1000);
return new SqlString(latitude + ", " + longitude);
}
}
I have built and deployed the function successfully. So I tried executing the function in the SQL server as follows:
SELECT dba.dbo.GetLatLong('3366 Cherry Avenue','Zion','WI','54963')
When I do so the following security expression is raised
A .NET Framework error occurred during execution of user-defined routine or aggregate "GetLatLong":
System.Security.SecurityException: Request for the permission of type 'System.Net.WebPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
System.Security.SecurityException:
at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
at System.Security.CodeAccessPermission.Demand()
at System.Net.HttpWebRequest..ctor(Uri uri, ServicePoint servicePoint)
at System.Net.HttpRequestCreator.Create(Uri Uri)
at System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase)
at latlong.GetLatLong(String address, String city, String state, String zip).
I can see that there is a problem with the security permissions. But beyond that I do not see the way to fix the exception.
Any help is appreciated.
Solution
OTHER TIPS
You need to declare your procedure with EXTERNAL_ACCESS
* permission:
EXTERNAL_ACCESS
assemblies have the same permissions asSAFE
assemblies, with the additional ability to access external system resources such as files, networks, environmental variables, and the registry.
(My emphasis)
*Or UNSAFE
, but I'd say EXTERNAL_ACCESS
unless or until it's demonstrated that you actually needed UNSAFE
.
Run this in sql:
ALTER DATABASE databasename SET TRUSTWORTHY ON
USE master
GO
grant external access assembly to [domain\computerusername]
grant external access assembly to sa