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:

First experiences with TypeScript in Visual Studio 2013 using jQuery and KnockoutJS libraries

For one customer, I wanted to create a POC to showcase the compile-time error checking advantages of TypeScript.

First of all: Visual Studio 2013 with Cumulative Update 4 is not enough to get the latest version of TypeScript, so you need to download it from TypeScript 1.4 for Visual Studio 2013. It is required to correctly compile some of the TypeScript definition files that will be included later.

Then it's possible to start creating a new MVC application. It includes by default NuGet packages for some common JavaScript libraries: jQuery, jQuery UI and Knockout JS, but it's possible to remove them or add new ones. These libraries are included by the MVC shared view _Layout.cshtml via bundle inclusions. The bundles are defined in App_Start/BundleConfig class.

To be able to use these libraries in our TypeScript files (getting compile-time error checking and Intellisense suggestions) it's necessary to include the .d.ts files, that are definition files with the purpose of use non-TypeScript libraries in TypeScript files. They can be found in the GitHub project DefinitelyTyped, but it's better to include them via NuGet packages (search for example for TypeScript jQuery, and so on).

Now following for example the example in TypeScript and JQuery example, I create a MyApp.ts file and paste the code here below (it's also possible to download the file MyApp.ts (392B):

/// <reference path="jquery.d.ts" />
 
class Person {
 
constructor(name:string)
{
this.name=name;
}
name: string;
}
 
function greeter (person:Person){
return "hallo "+person.name;
}
 
var person=new Person("bert");
 
 
$(document).ready(function(){
var message = greeter(person);
$("#status")[0].innerHTML=message;
});


As this file is created, a correspondent JavaScript file MyApp.js should be created.

Without including this file in the Visual Studio solution, it's possible to include this file in our shared _Layout, or better include it in one bundle.

At this point running the program, an alert, result of our MyApp code, should be displayed.


Notes so far in my research:

  • even if we have the .d.ts file, the original JavaScript files must be included. The .d.ts file is only a bridge to allow to use these libraries in the new TypeScript files, as described in Using jQuery plugin in TypeScript.
  • the .d.ts file can have a version different from the included JavaScript files, so when including these modules, it can be tricky to select the correct NuGet version. Else we can have a misalignment between the real JavaScript file and the hints suggested by the TypeScript compiler.

The better reference I have found to learn TypeScript is the TypeScript Handbook.

Visual Studio 2013: how test the performance of the html UI

As new solutions are pushing more and more the html UI, with various JavaScript and AJAX calls to complicate the scenario, analyzing the performance of the UI requires new tools.

For this, in Visual Studio 2013 you can find the HTML UI Responsiveness Profiler.


Here a few links on this topic:

Knockout.js: first experience

For a project, I have started using Knockout.js.
This is a library to build UIs starting from a data model that is binded to html templates.

To start using the library, there is a list of articles that must be read:

And finally a few notes I have understood:
  • Visible controls only the html style, but you have always the binding.
    If you don't want to bind something (for example because you have null objects), use the if construct
Other links:

JavaScript: console.log error

When working in JavaScript I have done output with console.log, but after that my page was working correctly only in debug mode.

I have found the solution in the page What is console.log and how do I use it?: the reason is that in Internet Explorer up to version 8, console.log is defined only in debug mode.

The solution is to add in your page the following JavaScript code:

   if(!window.console){ window.console = {log: function(){} }; }

JavaScript: how call cross-domain Ajax services

For one big company I have developed a project where I had to call JSON services from client html pages.

The particularity was that the services where hosted in a domain different from the domain of the hosted pages.

I have found some difficulties, and here is a list of tips:

  • Internet Explorer requires the use of the object XDomainRequest
  • if the calling page is served in https, the JSON service has to called in https too
  • the receiving service must accept cross-domain calls and must declare this adding the following header:
          Access-Control-Allow-Origin: *


Some (but not all) of this guidelines is in the article Cross Domain Ajax Request with JSON response for IE,Firefox,Chrome, Safari – jQuery.

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