Total Pageviews

Monday, December 2, 2013

IE 11 compatibility for ASP.NET Framework


With the release of IE 11 there has been compatibility issues with .NET Framework 4.0 and likewise every developer it has been a nightmare for all the sites that were not catering for this change/upgrade.

Issue: 
Internet Explorer version 11 (IE 11) has thrown many sites either on javascript variables or CSS styling with errors such as "
“The value of the property '' is null or undefined, not a Function object”

Cause:
Internet Explorer 11 does not recognize .NET Framework properly.

Resolution:
This issue can be fixed by adding "App_Browsers" folder into your website or web application project.

If App_Browsers folder does not exist in your current solution/website/project, then follow these steps:

1. Right Click on your project/website name 
2. Go to Add 
3. Go to "Add ASP.NET folder
4. Select "App_Browsers"

Otherwise:
1. Right click on "App_Browsers" folder 
2. Add New Item
3. Select browser file, name it ie11.browser
4. Copy the following code(red text) into ie11.browser file

CODE TO COPY:
<browsers>
    <browser id="IE11" parentID="Mozilla">
        <identification>
            <userAgent match="Trident\/7.0; rv:(?'version'(?'major'\d+)(\.(?'minor'\d+)?)(?'letters'\w*))(?'extra'[^)]*)" />
            <userAgent nonMatch="IEMobile" />
        </identification>
        <capture>
            <userAgent match="Trident/(?'layoutVersion'\d+)" />
        </capture>
        <capabilities>
            <capability name="browser"              value="IE" />
            <capability name="layoutEngine"         value="Trident" />
            <capability name="layoutEngineVersion"  value="${layoutVersion}" />
            <capability name="extra"                value="${extra}" />
            <capability name="isColor"              value="true" />
            <capability name="letters"              value="${letters}" />
            <capability name="majorversion"         value="${major}" />
            <capability name="minorversion"         value="${minor}" />
            <capability name="screenBitDepth"       value="8" />
            <capability name="type"                 value="IE${major}" />
            <capability name="version"              value="${version}" />
        </capabilities>
    </browser>

    <!-- Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11,0) like Gecko -->
    <browser id="IE110" parentID="IE11">
        <identification>
            <capability name="majorversion" match="11" />
        </identification>

        <capabilities>
            <capability name="ecmascriptversion"    value="3.0" />
            <capability name="jscriptversion"       value="5.6" />
            <capability name="javascript"           value="true" />
            <capability name="javascriptversion"    value="1.5" />
            <capability name="msdomversion"         value="${majorversion}.${minorversion}" />
            <capability name="w3cdomversion"        value="1.0" />
            <capability name="ExchangeOmaSupported" value="true" />
            <capability name="activexcontrols"      value="true" />
            <capability name="backgroundsounds"     value="true" />
            <capability name="cookies"              value="true" />
            <capability name="frames"               value="true" />
            <capability name="javaapplets"          value="true" />
            <capability name="supportsCallback"     value="true" />
            <capability name="supportsFileUpload"   value="true" />
            <capability name="supportsMultilineTextBoxDisplay" value="true" />
            <capability name="supportsMaintainScrollPositionOnPostback" value="true" />
            <capability name="supportsVCard"        value="true" />
            <capability name="supportsXmlHttp"      value="true" />
            <capability name="tables"               value="true" />
            <capability name="supportsAccessKeyAttribute"    value="true" />
            <capability name="tagwriter"            value="System.Web.UI.HtmlTextWriter" />
            <capability name="vbscript"             value="true" />
        </capabilities>
    </browser>
</browsers>

5. Save the file and build the project(recommended but not mandatory, but on saving the file all your sessions will be disposed)

6. Re-test your project.

I hope this would help many developers and save the tiring time of re-search.

Your feedback will be much appreciated. 


Cheers

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!

Friday, April 27, 2012

Uploading Large files in asp.net and IIS 7.0 and higher

Hi,

I'm hoping this would be helping out many of alike programmers facing file upload issue with asp.net, as it took me few different troubleshooting paths to eventually get large files uploading functional for the applications that were working perfectly fine UNTIL I moved these application to IIS 7.0 from IIS 6.0.

Recently I migrated our hosting servers from IIS 6.0 to IIS 7.5 including all the source code and mark-up files(in c#.net). Since that day applications with "FileUpload" functionality started displaying "Page cannot be displayed" message when ever large files were uploaded.

I tried increasing executionTimeOut and maxRequestLength (which would be the first thought in every developer's mind) but it didn't worked. Finally the solution to this issue (asp.net file upload on IIS 7.0 or higher) turned out to be the changed web.config element to cater larger files!!

In <system.webServer> you need add the following line of code and it would definitely work for large uploads:
       <security>
            <requestFiltering>
                <requestLimits maxAllowedContentLength="2294967296" />
            </requestFiltering>
        </security>

Make sure your session timeout value is high enough to keep the upload happening else your page would expire regardless.

Thank you,