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.

Was it helpful?

Solution

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

OTHER TIPS

You need to declare your procedure with EXTERNAL_ACCESS* permission:

EXTERNAL_ACCESS assemblies have the same permissions as SAFE 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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top