Xamarin PCL Calling an ASMX web service from Windows Authentication

The core feature of an app I was working on in Xamarin was to gather data from a web service. This web service was created awhile ago in ASMX. After creating a class with SlSvcUtil.exe from the WSDL I imported it into the PCL, as I had for the many other times I had referenced a web service.

This did not work, as the class generated by .NET was not compatible with my PCL so I had to find another way to talk to the web service. I decided to use an HttpWebRequest to POST my information directly to server and read the response. This is easily done in a PCL. The issue I came across was the server being protected by Windows Authentication.

First you have to configure the server to prioritize the NTLM provider for Windows authentication. Open the IIS Manager and configure the site.

Under IIS, select Authentication.

IIS Authentication

Select the Windows Authentication item and edit the providors.

IIS Authentication Providers

Move NTLM to the top.

Prioritize NTLM Authentication

First we have to set up the authentication to use NTLM.

        Uri requestUri = null;
        Uri.TryCreate("http://example.com/WebService.asmx/GetData", UriKind.Absolute, out requestUri);

        NetworkCredential nc = new NetworkCredential("username", "password");
        CredentialCache cache = new CredentialCache();

        cache.Add(requestUri, "NTLM", nc);

Now that we’ve set up our network credentials, we can build the string to POST data to the web service.

        StringBuilder postData = new StringBuilder();
        postData.Append("apiKey=" + Uri.EscapeUriString(apiKey) + "&");
        postData.Append("moreData=" + Uri.EscapeUriString(moreData));

The next step is to create the HttpWebRequest and configure it to POST data and use the proper credentials.

       HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUri);

        request.Method = "POST";
        request.Credentials = nc;

Finally, we convert the data we are POSTing to the server into a byte array and write it to the stream used by the HttpWebRequest

        byte[] data = Encoding.UTF8.GetBytes(postData.ToString());
        Stream requestStream = await request.GetRequestStreamAsync();
        requestStream.Write(data, 0, data.Length);

Finally, we use the HttpWebRequest to POST to the server and retrieve the JSON.

try
    {
        var response = await request.GetResponseAsync();
        var stream = response.GetResponseStream();

        StreamReader reader = new StreamReader(stream);
        var xml = reader.ReadToEnd();

        // ASMX returns the JSON as XML, parse that out to retrieve the plain JSON.
        System.Xml.Linq.XDocument doc = XDocument.Parse(xml);
        return doc.Root.Value;


    }
    catch (WebException ex)
    {
        StreamReader reader = new StreamReader(ex.Response.GetResponseStream());
        var message = reader.ReadToEnd();

        System.Diagnostics.Debug.WriteLine(ex.Message);
        return null;
    }
}

Here is all the code all to return the JSON data in one place.

string GetDataFromAPi()
{
        string apiKey = "specialvalue";
        string moreData = "dataForTheAPI 

        Uri requestUri = null;
        Uri.TryCreate("http://example.com/WebService.asmx/GetData", UriKind.Absolute, out requestUri);

        NetworkCredential nc = new NetworkCredential("username", "password");
        CredentialCache cache = new CredentialCache();

        cache.Add(requestUri, "NTLM", nc);

        StringBuilder postData = new StringBuilder();
        postData.Append("apiKey=" + Uri.EscapeUriString(apiKey) + "&");
        postData.Append("moreData=" + Uri.EscapeUriString(moreData));


        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUri);

        request.Method = "POST";
        request.Credentials = nc;

        byte[] data = Encoding.UTF8.GetBytes(postData.ToString());
        Stream requestStream = await request.GetRequestStreamAsync();
        requestStream.Write(data, 0, data.Length);

        request.ContentType = "application/x-www-form-urlencoded";


        try
        {
            var response = await request.GetResponseAsync();
            var stream = response.GetResponseStream();

            StreamReader reader = new StreamReader(stream);
            var xml = reader.ReadToEnd();

            // ASMX returns the JSON as XML, parse that out to retrieve the plain JSON.
            System.Xml.Linq.XDocument doc = XDocument.Parse(xml);
            return doc.Root.Value;


        }
        catch (WebException ex)
        {
            StreamReader reader = new StreamReader(ex.Response.GetResponseStream());
            var message = reader.ReadToEnd();

            System.Diagnostics.Debug.WriteLine(ex.Message);
            return null;
        }
}

Written on January 16th, 2015 by Dan Walker
Tags: xamarin, mobile, pcl.

Want to read more?

If you’ve enjoyed what you’ve seen so far, you might like some of my other posts. Visit the archive to see all of my past writings.

Blog Archive »
 

About the Author

Dan Walker is a programmer from Grand Rapids, MI. He works at Gordon Food Service.

More About Dan »

Get in touch