SJAX Call

While visiting Asp.net forum, I found an interesting request, A forum member is trying to implement some validator controls where the member wants to call a Web Service method, since the nature of Asp.net Ajax is asynchronous the call does not return instantly. In the reply, another member from Microsoft provides some code which uses XMLHttpRequest to make a Synchronous call to web service. Certainly it does the Job but there is no flavor of Asp.net Ajax Framework. I am not sure the MS guy really knows that the Asp.net Ajax Framework supports Custom Web Request executor, by default Asp.net Ajax uses Sys.Net.XMLHttpExecutor for server side method calling. So I decide to create a small class which can be used with the Asp.net Ajax Framework to call a Server Side method synchronously. The Following shows the code how to call a server side method synchronously:

function GetWebRequest() { var resultElement = $get('ResultId');

resultElement.innerHTML = '';

// Instantiate a WebRequest.
var wRequest = new Sys.Net.WebRequest();
// Set the request URL.
wRequest.set\_url('getTarget.aspx');
// Set the request verb.
wRequest.set\_httpVerb('GET');

var executor = new Sys.Net.XMLHttpSyncExecutor(); // This is the Custom Executor
wRequest.set\_executor(executor);
// Execute the request.
wRequest.invoke();

if (executor.get\_responseAvailable()) 
{
    // Clear the previous results. 
    resultElement.innerHTML = '';
    // Display Web request status. 
    resultElement.innerHTML += 'Status: \[' + executor.get\_statusCode() + ' ' + executor.get\_statusText() + '\]' + '<br/>';
    // Display Web request headers.
    resultElement.innerHTML +=  'Headers: ';
    resultElement.innerHTML += executor.getAllResponseHeaders() + '<br/>';
    // Display Web request body.
    resultElement.innerHTML +=  'Body:';

    if(document.all)
    {
        resultElement.innerText += executor.get\_responseData();
    }
    else
    {
        resultElement.textContent += executor.get\_responseData();
    }
}

}

As you can see here is no onComplete handler since this is a synchronous call, I have just ported this example which is found with Asp.net Ajax Documentation with the Custom executor. The following shows the code of this custom executor.

Type.registerNamespace('Sys.Net');

Sys.Net.XMLHttpSyncExecutor = function() { Sys.Net.XMLHttpSyncExecutor.initializeBase(this);

this.\_started = false;
this.\_responseAvailable = false;

this.\_onReceiveHandler = null;

this.\_responseData = null;
this.\_statusCode = null;
this.\_statusText = null;
this.\_headers = null;

}

Sys.Net.XMLHttpSyncExecutor.prototype = { get_aborted : function() { if (arguments.length !== 0) throw Error.parameterCount();

    return false;
},

get\_responseAvailable : function()
{
    if (arguments.length !== 0) throw Error.parameterCount();

    return this.\_responseAvailable;
},

get\_responseData : function()
{
    if (arguments.length !== 0) throw Error.parameterCount();

    if (!this.\_responseAvailable)
    {
        throw Error.invalidOperation(String.format(Sys.Res.cannotCallBeforeResponse, 'get\_responseData'));
    }

    return this.\_responseData;
},

get\_started : function()
{
    if (arguments.length !== 0) throw Error.parameterCount();

    return this.\_started;
},

get\_statusCode : function()
{
    if (arguments.length !== 0) throw Error.parameterCount();

    if (!this.\_responseAvailable)
    {
        throw Error.invalidOperation(String.format(Sys.Res.cannotCallBeforeResponse, 'get\_statusCode'));
    }

    return this.\_statusCode;
},

get\_statusText : function()
{
    if (arguments.length !== 0) throw Error.parameterCount();

    if (!this.\_responseAvailable)
    {
        throw Error.invalidOperation(String.format(Sys.Res.cannotCallBeforeResponse, 'get\_statusText'));
    }

    return this.\_statusText;
},

get\_xml : function()
{
    if (arguments.length !== 0) throw Error.parameterCount();

    if (!this.\_responseAvailable)
    {
        throw Error.invalidOperation(String.format(Sys.Res.cannotCallBeforeResponse, 'get\_xml'));
    }

    var xml = this.\_responseData;

    if ((!xml) || (!xml.documentElement))
    {
        xml = new XMLDOM(this.\_responseData);

        if ((!xml) || (!xml.documentElement))
        {
            return null;
        }
    }
    else if (navigator.userAgent.indexOf('MSIE') !== -1)
    {
        xml.setProperty('SelectionLanguage', 'XPath');
    }

    if ((xml.documentElement.namespaceURI === "http://www.mozilla.org/newlayout/xml/parsererror.xml") &&
        (xml.documentElement.tagName === "parsererror"))
    {
        return null;
    }

    if (xml.documentElement.firstChild && xml.documentElement.firstChild.tagName === "parsererror")
    {
        return null;
    }

    return xml;
},

executeRequest : function()
{
    if (arguments.length !== 0) throw Error.parameterCount();

    if (this.\_started)
    {
        throw Error.invalidOperation(String.format(Sys.Res.cannotCallOnceStarted, 'executeRequest'));
    }

    var webRequest = this.get\_webRequest();

    if (webRequest === null)
    {
        throw Error.invalidOperation(Sys.Res.nullWebRequest);
    }

    var body = webRequest.get\_body();
    var headers = webRequest.get\_headers();
    var verb = webRequest.get\_httpVerb();

    var xmlHttpRequest = new XMLHttpRequest();
    this.\_onReceiveHandler = Function.createCallback(this.\_onReadyStateChange, {sender:this, xmlHttp:xmlHttpRequest});
    this.\_started = true;
    xmlHttpRequest.onreadystatechange = this.\_onReceiveHandler;
    xmlHttpRequest.open(verb, webRequest.getResolvedUrl(), false); // False to call Synchronously

    if (headers)
    {
        for (var header in headers)
        {
            var val = headers\[header\];

            if (typeof(val) !== "function")
            {
                xmlHttpRequest.setRequestHeader(header, val);
            }
        }
    }

    if (verb.toLowerCase() === "post")
    {
        if ((headers === null) || !headers\['Content-Type'\])
        {
            xmlHttpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        }

        if (!body)
        {
            body = '';
        }
    }

    xmlHttpRequest.send(body);
},

getAllResponseHeaders : function()
{
    if (arguments.length !== 0) throw Error.parameterCount();

    if (!this.\_responseAvailable)
    {
        throw Error.invalidOperation(String.format(Sys.Res.cannotCallBeforeResponse, 'getAllResponseHeaders'));
    }

    return this.\_headers;
},

\_onReadyStateChange : function(e)
{
    if (e.xmlHttp.readyState === 4)
    {
        e.sender.\_responseAvailable = true;
        e.sender.\_responseData = e.xmlHttp.responseText;
        e.sender.\_statusCode = e.xmlHttp.status;
        e.sender.\_statusText = e.xmlHttp.statusText;
        e.sender.\_headers = e.xmlHttp.getAllResponseHeaders();

        e.xmlHttp.onreadystatechange = Function.emptyMethod;
        e.sender.\_onReceiveHandler = null;

        e.sender.\_started = false;
    }
}

}

Sys.Net.XMLHttpSyncExecutor.registerClass('Sys.Net.XMLHttpSyncExecutor', Sys.Net.WebRequestExecutor);

if (typeof(Sys) != 'undefined') { Sys.Application.notifyScriptLoaded(); }

You can also download the full code listing from this link. Since the nature of the Call is Synchronous we can call it Synchronous JavaScript and XML or SJAX.

kick it on DotNetKicks.com

This article is part of the GWB Archives. Original Author: Kazi Manzur Rashid

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.