JavaScript CORS used to call asmx web-services

The following example shows how to implement a server implementing an asmx web-service and a JavaScript client invoking it from a different domain. The particularity is that this cross-site invocation requires CORS (Cross-origin resource sharing), supported in IE8+ and other popular browsers.


The server (part 1)

To create the server, I create in Visual Studio an empty web application. Then I add a Search.asmx web-service, adding the following method:

[WebMethod]

public string DateTimeNow(string Where)

{

return DateTime.Now.ToLongTimeString() + " in " + Where;

}

Then to test it I easily deploy it to the Azure Website http://corsserviceapplication.azurewebsites.net/.


The client

To create the client, I create in Visual Studio another empty web application. I add a reference to the jQuery NuGet package, then I add a simple html page and an App.js file.

Here the html page:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<title>My CORS Client Page</title>

<script src="Scripts/jquery-2.1.4.js"></script>

<script src="Scripts/App.js"></script>

</head>

<body>

<input id="city" type="text" value="Basel" />

<input type="button" value="Press here" onclick="test_cors_client(false, document.getElementById('city').value);" />

</body>

</html>


The App.js file is copied here too:
function test_cors_client(simple, where)
{
function escapeHTML(str) {
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

var soapEnv, soapAction;
if (simple) {
soapEnv =
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"> \
<soap:Body> \
<HelloWorldResponse xmlns=\"http://tempuri.org/\"> \
<HelloWorldResult>string</HelloWorldResult> \
</HelloWorldResponse> \
</soap:Body> \
</soap:Envelope>";
soapAction = "http://tempuri.org/HelloWorld";
}
else {
soapEnv =
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"> \
<soap:Body> \
<DateTimeNow xmlns=\"http://tempuri.org/\"> \
<Where>" + escapeHTML(where) + "</Where> \
</DateTimeNow> \
</soap:Body> \
</soap:Envelope>";
soapAction = "http://tempuri.org/DateTimeNow";
}

$.ajax({
//url: "http://localhost:8118/Search.asmx",
url: "http://corsserviceapplication.azurewebsites.net/Search.asmx",
type: "POST",
dataType: "xml",
data: soapEnv,
complete: processResult,
contentType: "text/xml; charset=\"utf-8\"",
headers: {
"SOAPAction": soapAction
}
});
function processResult(xData, status) {
if (status != "success") {
alert("error\n\n" + xData.responseText);
return;
}
alert("success\n\n" + xData.responseText);
}
/* var createCORSRequest = function (method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Most browsers.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// IE8 & IE9
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
};

//var url = "http://localhost:8118/Search.asmx";
var url = 'http://corsserviceapplication.azurewebsites.net/Search.asmx';
var method = 'POST';
var xhr = createCORSRequest(method, url);
xhr.setRequestHeader("Content-Type", "text/xml; charset=\"utf-8\"");

xhr.onload = function (e) {
// Success code goes here.
alert('success\n\n' + e.target.responseText);
};

xhr.onerror = function (e) {
// Error code goes here.
alert('error\n\n' + e.target);
};

xhr.setRequestHeader("SOAPAction", soapAction);
xhr.send(soapEnv);*/
}

This file contains both the jQuery implementation using $.ajax, and the XmlHttpRequest + XDomainRequest produced using test-cors.org.
Trying the example, you will see that it works when the example is run locally (with Service.asmx copied in the same client website), but not with CORS.

The server (part 2)

To enable CORS on the server, we need to add additional headers on the server, and one quick method is to modify the web.config as here below:

<?xml version="1.0" encoding="utf-8"?>

<!--

For more information on how to configure your ASP.NET application, please visit

http://go.microsoft.com/fwlink/?LinkId=169433

-->

<configuration>

<system.web>

<compilation debug="true" targetFramework="4.5" />

<httpRuntime targetFramework="4.5" />

</system.web>


<system.webServer>

<httpProtocol>

<customHeaders>

<add name="Access-Control-Allow-Origin" value="*" />

<add name="Access-Control-Allow-Headers" value="Content-Type, SOAPAction" />

</customHeaders>

</httpProtocol>

</system.webServer>

</configuration>


Now it will be possible to invoke the Search.asmx web-service even from another domain through CORS and here is the zip file containing the complete solution: CORS_Test.zip (704.8KB).


A few links used for reference:

SharePoint and JavaScript CSOM

I'm relizing that I'm spending too much time googling the same topics over and over (on JavaScript programming), so I list here a few solution I need in a recurrent way.

 

JavaScript: how understand if page is opened in iFrame, and get its url

 

Javascript: how get url parameters

  • function to get query string parameters:
    function getURLParameter(name) {
    return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null
    }
  • source: How to get URL parameters with Javascript?

 

Javascript: function to format numbers

 

Javascript: function to format date-times

 

Javascript: how html encode strings

 

jQuery: how write a custom filter method

jQuery: creating extensions

When developing with jQuery, I often need to verify selectors, so I usually write something like this:

$('my selector').css('background-color', 'red');

To save some typing, I wanted to create a jQuery extension so I have followed the tutorial Writing Your Own jQuery Plugins and here is my extension:

(function($) {

   // This function makes the background color red (used for debug)
   $.fn.red = function() {
      this.each(function() {
         $(this).css('background-color', 'red');
      });
   };

   // This function alerts the length of the collection items (used for debug)
   $.fn.alertLength = function() {
      alert($(this).length);
   };

   // This function alerts each item in the collection (used for debug)
   $.fn.foreachAlert = function() {
      this.each(function(index, value) {
         alert('' + index + ': ' + value);
      });
   };

 }(jQuery));

SharePoint: getTagFromIdentifierAndTitle

When developing in SharePoint using the client-script object model, for sure you have met the function getTagFromIdentifierAndTitle, proposed by Microsoft and copied in many websites.

The basic implementation can be found in many websites, and the article Tags and Identifiers for getTagFromIdentifierAndTitle Function is only one of many examples.

 

But this function doesn't handle choice fields displayed as radio buttons.

So I have found another other implementation in the blog post Trigger JavaScript Events When a Choice (Radio Button) SharePoint Field Type is Clicked.

Regions in Notepad++

While editing JavaScript files with Notepad++, I have noticed that like in Visual Studio there is the nice feature to collapse function methods.

But so I thought, how to implement the "regions" that I can define in C# files?

 

I have found a nice trick in one of the answers at the question notepad++ user defined regions with folding: simply add a comment and then the opening and closure brackets.

In my example it could be:

  • ///////////////////////////////////////////////////////////////////////{ BEGIN of my region
  • ///////////////////////////////////////////////////////////////////////} END of my region