Introduction
This article shows how to consume a Microsoft AJAX web service (System.Web.Script.Services.ScriptService
) to call synchronously at the client side using the XMLHttpRequest
object and JavaScript.
Using a synchronous call, we can get rid of the problems of validating duplicate names in a custom validator without changing the code-behind. Many developers like me face this problem and have to find alternate solutions.
Using the Code
Here is the JavaScript code following the function GetSynchronousJSONResponse
that calls the URL and posts the POST data synchronously using an XMLHttpRequest
.
function GetSynchronousJSONResponse(url, postData) {
var xmlhttp = null;
if (window.XMLHttpRequest)
xmlhttp = new XMLHttpRequest();
else if (window.ActiveXObject) {
if (new ActiveXObject("Microsoft.XMLHTTP"))
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
else
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
url = url + "?rnd=" + Math.random();
xmlhttp.open("POST", url, false);
xmlhttp.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xmlhttp.send(postData);
var responseText = xmlhttp.responseText;
return responseText;
}
How to call GetSynchronousJSONResponse()
First, lets do a simple server call to get a single constant string. To understand the following code snippets, you need a bit of knowledge of JSON and how JSON represents an object. "HelloWorld
" is the method name in the code-behind of the web service.
function HelloWorld() {
var result = GetSynchronousJSONResponse(
'<%= Page.ResolveUrl("~/WebService.asmx/HelloWorld") %>', null);
result = eval('(' + result + ')');
alert(result.d);
}
Code-behind:
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
In the above code, the eval()
function parses the JSON string in to the JavaScript object.
Let's move to a bit more complex situation. If you want to pass data to the server and get the server to return processed data back to display to the user:
function HelloMe() {
var result = GetSynchronousJSONResponse('<%= Page.ResolveUrl(
"~/WebService.asmx/HelloMe") %>',
'{"Name":"' + document.getElementById('txtName').value + '"}');
result = eval('(' + result + ')');
alert(result.d);
}
Code-behind:
[WebMethod]
public string HelloMe(string Name)
{
return "Hello " + Name + " !";
}
In the above code, if the input contains the name "Sandip", then the JSON string to post will be {"Name":"Sandip"}
. Here, "Name" is an argument of the web method which is defined in the code-behind of the web service file. We can only use primitive data types like string
, int
, decimal
, etc. We can also pass multiple arguments, for example, {"Name":"Sandip","Age":"23"}
, to pass both the name and age.
Finally, let us use it in a custom validator. Here, the return type of the web method is bool
according to the condition.
function CheckForDuplicateInDB(sender, arg) {
var result = GetSynchronousJSONResponse('<%= Page.ResolveUrl(
"~/WebService.asmx/CheckName") %>',
'{"Name":"' + arg.Value + '"}');
result = eval('(' + result + ')');
arg.IsValid = !result.d;
}
ASPX markup:
<asp:TextBox ID="txtCheckName" runat="server" Text="Validator"></asp:TextBox>
<asp:CustomValidator ID="cvName" ControlToValidate="txtCheckName"
ClientValidationFunction="CheckForDuplicateInDB"
EnableClientScript="true" runat="server" Display="Static"
ToolTip="Name is Duplicate." Text="*">
</asp:CustomValidator>
<asp:Button ID="btnClickMe" runat="server" Text="ClickMe!" />
Code-behind:
[WebMethod]
public bool CheckName(string Name)
{
return (Name == "Validator");
}
Additionally, here is the code to handle/display server side errors:
function CallError() {
var result = GetSynchronousJSONResponse('<%= Page.ResolveUrl(
"~/WebService.asmx/CallError") %>', null);
result = eval('(' + result + ')');
if (typeof (result.d) == 'undefined')
alert(result.Message);
else
alert(result.d);
}
Code-behind:
[WebMethod]
public string CallError()
{
int i = 0;
int j = 5 / i;
return "Call Error";
}
References
History
- 22 Oct 2008: Posted to The Code Project.