Total Pageviews

Monday, April 22, 2013

Soap Header Authentication for Web Services in ASP.NET


Hi All,

I will be discussing web service authentication in this article, where you can host your web service publically but it can only be accessed by passing pre-assigned username, password and secure parameter. 

So speaking simple SOAP web services, following are the steps that will make your publically available web service, a secured web service.

When you choose to create a new web service(for .NET 2.0/3.0/3.5), you will see the following Service1.asmx code-behind. (Note: I've added "System.Web.Services.Protocols" namespace and "#region" tag in the default code.



This is an example of default web service code which will let HelloWorld() method to be consumed without any authentication, once this web service is published over the App Server(local IIS or over Internet).

By adding couple of lines of code we can make the existing web service to be secure(i.e.by enforcing username and password via SOAP Header).

So let's pick some username and password for the web service and place it within <appSettings> tag in Web.config file. 

  <appSettings>
    <add key="ff_username" value="user1"/>
    <add key="ff_password" value="User!123"/>
  </appSettings>

Now to implement this username and password, we need to modify the current web service code as shown in highlighted boxes below:


Now this web service is secured with customer username and password. After a successful build you can deploy/publish this web service on your IIS(local or Internet).

HOW TO TEST IF THE ABOVE WEBSERVICE IS WORKING WITH USERNAME & PASSWORD AUTHENTICATION

You can create a "Test Project" where you can add the service reference by right clicking on "Web Reference"--> choosing "Add Web Reference" and providing the URL of your currently deployed web service.

Assuming that you have given the web reference name of your web service(under Test Project) as "prod", it should look something as shown below.


Now in the code-behind of your "Default.aspx.cs", create the web service instance and consume the HelloWorld() and display it in Label.Text as shown below:

As stated in commented text, if your web service fails the authentication it will display "Authentication Failed" otherwise it will display "Hello World".


Cheers :-)

Monday, April 15, 2013

Consume Google Maps geoCode API Web Service in .NET

Hi,

In this post I will be talking about geocoding the address and extracting XML node values such as "Google defined address(Formatted_Address)", "Latitude", "Longitude" etc.

As we all must have searched some address location on Google Maps so I'm assuming you all to be aware with the basic look & feel and working of Google Maps.

Mostly we enter one address at a time on "Google Maps" UI, which in turn, redirects and points the location using markers.
In the scenario where you have to search for specific nodes or node-values i.e. customized search for any associated value for a particular address, it may be tedious and frustrating.

So lets see how we can use the freely available "Google Maps API" and attain our desired results.
For full documentation on Google API Web Services visit Google API 

The web service request is made in the format given below:

http://maps.googleapis.com/maps/api/service/output?parameters 

Although the same web service can also be access via HTTPS protocol in the format given below:
https://maps.googleapis.com/maps/api/service/output?parameters


For the browser to make web service call to Google Maps API, following url string is parsed where address take the parameter value {0}:
http://maps.google.com/maps/api/geocode/xml?address={0}&sensor=false 

To make it more simpler, I'm using Melbourne, Australia as the parameter value for address field. This will be interpreted by the system in the format:
http://maps.google.com/maps/api/geocode/xml?address=Melbourne,Australia&sensor=false

To see the results you can directly paste the above url into your browser and see the results
Google API Web Service Call Result
Results for Google API Web Service Call with Address as Melbourne, Australia

Now this XML result set gives you all the nodes that can be used, based on your requirements. But it's hard to manually change the address values when geocoding hundreds or thousands of addresses.

To overcome this scenario I opted for reading all the addresses from a text file in the format using while loop:
uniqueID:address
uniqueID:address
uniqueID:address

Method ReadAddressFromFile on PageLoad or Button Click


private void ReadAddressFromFile()
        {
            try
            {
                // Create an instance of StreamReader to read from a file.
                // The using statement also closes the StreamReader.
                using (StreamReader sr = new StreamReader(@"D:\geocode\Uploads\Address_1.txt"))
                {
                    String line;
                    string _address = "";
                    // Read and display lines from the file until the end of
                    // the file is reached.
                    while ((line = sr.ReadLine()) != null)
                    {
                        _recordCount++;
                        Session["_recordCount"] = _recordCount;
                        _merchantID = line.Split(':');
                        Session["_merchantId"] = _merchantID[0].ToString();
                 
                        _address = _address + line+"\n\n";
                        _address = _address.Replace("\t", " ");
                        Session["addressFromFile"] = _merchantID[1].ToString();
                        FindCoordinates();
                        _address = ""; //
                    }
           
                }
            }
            catch (Exception ex)
            {
                // Let the user know what went wrong.
            }
        }


In the above code snippet, on each line read "FindCoordinates" Method is been called where I'm passing ID and address after delimiting/tokenizing on ':' (If you remember uniqueID:address still :) )

Now let's see what's happening in FindCoordinates method...
Method FindCoordinates()


private void FindCoordinates()
        {
            try
            {
                url = String.Format("http://maps.google.com/maps/api/geocode/xml?address={0}&sensor=false", Session["addressFromFile"].ToString().Replace(" ", ","));
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream outputStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(outputStream, Encoding.ASCII);
                output = reader.ReadToEnd();

                response.Close();
                outputStream.Close();
                reader.Close();

                //write to File                            
                deSerializeResponse();
            }
            catch (Exception ex)
            {
                //Catch execptions here
            }
            finally
            {
               //clear any session values
            }
        }


In the above code snippet, web service call is made with address parameter from Session value "addressFromFile" which is assigned in ReadAddressFromFile method.


What Happens in deSerializeResponse Menthod?

Here's the snippet:


private void deSerializeResponse()
        {
            string _lat = "";
            string _long = "";
            string results = "";
            string formatted_address = "";
            string oldFileName = @"D:\geocode\Uploads\XMLOutput.txt";
            string newFileName = @"D:\geocode\Uploads\myXmFile.xml";
            File.Delete(oldFileName);
            // Write the string to a file.
            System.IO.StreamWriter file = new System.IO.StreamWriter(@"D:\geocode\Uploads\XMLOutput.txt");
            System.IO.StreamWriter wsResultFile = File.AppendText(@"D:\geocode\Uploads\WebServiceResult.txt");
            // Retrieve XML document

            XmlTextReader reader = new XmlTextReader(new StringReader(txtLatitude.Text));

            // Skip non-significant whitespace
            reader.WhitespaceHandling = WhitespaceHandling.Significant;
            file.WriteLine(txtLatitude.Text);

            file.Close();
            File.Delete(newFileName);
            File.Move(oldFileName, newFileName);
            XmlDocument xdXml = new XmlDocument();
            xdXml.Load(@"D:\geocode\Uploads\myXmFile.xml");
            //Make a nodelist
            XmlNodeList nodes = xdXml.SelectNodes("//GeocodeResponse/result"); //1
            foreach (XmlNode node in nodes)
            {
                formatted_address = node["formatted_address"].InnerText;
            }
            nodes = xdXml.SelectNodes("//GeocodeResponse/result/geometry/location"); //2
            foreach (XmlNode node in nodes)
            {
                _lat = node["lat"].InnerText;
                _long = node["lng"].InnerText;
            }
            results = Session["_merchantId"].ToString() + " | " + Session["addressFromFile"].ToString().Trim() + " | " + formatted_address + " | " + _lat + " | " + _long;        
            wsResultFile.WriteLine(results);
            wsResultFile.Close();
        }

"There are few files that I've created for myself so don't get confused in number of files been created in the above code snippet ;-) "


Mainly, you are looking at "myXmFile.xml" from where iterate through each node of GeocodeResponse>>result (refer 1 in the code snippet) and further iterate within geometry>>location node(refer 2) to read latitude("lat") and longitude("lng") values.


Why I used uniqueID?
Because, all these geocode results will be uploaded into database with these ID mappings.

The above scenario will be often seen for web apps or mobile apps where you have to list down addresses or locations based on "GPS current location", "Postcode", "region" searches.

Cheers!