Introduction
Here is a full example of how to use JS to call a webservice by both SOAP and JSON.
Background
Now almost everybody talks about Ajax and webservices. I tried too and I wrote a JS to do the work! After reading my article, you will find things are really simple!
There is something different about my sample. It really works in Internet Explorer 6, Internet Explorer 7, Opera, and also Netscape. You will find that in Firefox3, it doesn't support the synchronism function to call a webservice. I also find that we can't create more than one instance of xmlhttprequest
object in Internet Explorer 6. I fixed the problem. It really works well, but is not supported in Internet Explorer 5, because it does not support the push()
function. I haven't tried to test it in Internet Explorer 5.
You might want to know that xmlhttprequest
does not support the cross-domain webservice.
Using the Code
Here is the file of kuuy.SoapRequest.js:
(function() {
var Namespace = {
Register: function(_Name) {
var o = window;
var x = false;
for (var a = _Name.split("."); a.length > 0; ) {
var s = a.shift();
if (a.length == 0) { if (o[s]) { x = true; } }
if (!o[s]) { o[s] = {}; }
o = o[s];
}
if (x) { return 1; }
}
}
Namespace.Register("kuuy");
var xmlPId = null;
var xmlHttp = (function() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
}
else {
if (xmlPId) {
return new ActiveXObject(xmlPId);
}
else {
var parserIds = ["Msxml2.XMLHTTP.6.0",
"MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
for (var pid in parserIds) {
try {
xmlPId = pid;
return new ActiveXObject(parserIds[pid]);
} catch (e) { }
}
throw new Error("don't support the xmlrequest object~!");
}
}
})();
kuuy.Parameter = function() {
return {
Name: null,
Value: null,
Init: function() {
if (arguments[0].length == 2)
{ this.Name = arguments[0][0]; this.Value = arguments[0][1]; }
return this;
}
}.Init(arguments);
}
kuuy.SOAPRequest = function() {
return {
URL: null,
Method: null,
Params: null,
Callback: null,
WSDLS: null,
Init: function() {
switch (arguments[0].length) {
case 2:
this.URL = arguments[0][0];
this.Callback = arguments[0][1];
break;
case 3:
this.URL = arguments[0][0];
this.Method = arguments[0][1];
this.Callback = arguments[0][2];
this.WSDLS = new Array();
break;
}
this.Params = new Array();
return this;
},
AddParam: function()
{
switch (arguments.length) {
case 1: this.Params.push(arguments[0]); break;
case 2: this.Params.push
(new kuuy.Parameter(arguments[0], arguments[1])); break;
}
},
Open: function() {
var obj = this;
if (this.WSDLS) {
var wsdl = this.WSDLS[this.URL];
if (!wsdl) {
xmlHttp.open
("GET", this.URL + "?wsdl", true);
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200 || xmlHttp.status == 0) {
(function() { obj.Post.call(obj, xmlHttp.responseXML); })();
}
}
};
xmlHttp.send(null);
}
else
(function() { obj.Post.call(this); })();
}
else {
var data = "";
for (var par in this.Params) {
data += this.Params[par].Name +
"=" + this.Params[par].Value;
}
xmlHttp.open("POST", this.URL, true);
xmlHttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("Content-Length", data.length);
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200 || xmlHttp.status == 0) {
obj.Callback(xmlHttp.responseText);
}
}
}
xmlHttp.send(data);
}
},
Post: function() {
if (!this.WSDLS[this.URL])
this.WSDLS[this.URL] = arguments[0];
var wsdl = this.WSDLS[this.URL];
var ns = (wsdl.documentElement.attributes["targetNamespace"] +
"" == "undefined") ?
wsdl.documentElement.attributes.getNamedItem
("targetNamespace").nodeValue :
wsdl.documentElement.attributes["targetNamespace"].value;
var soapaction = ((ns.lastIndexOf("/")
!= ns.length - 1) ? ns + "/" : ns) + this.Method;
var parsXml = "";
for (var par in this.Params) {
parsXml += "<" + this.Params[par].Name + ">" +
this.Params[par].Value + "</" +
this.Params[par].Name + ">"; ;
}
var data = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<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>" +
"<" + this.Method + " xmlns=\"" + ns + "\">" +
parsXml +
"</" + this.Method + "></soap:Body></soap:Envelope>";
xmlHttp.open("POST", this.URL, true);
xmlHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttp.setRequestHeader("SOAPAction", soapaction);
xmlHttp.setRequestHeader("Content-Length", data.length);
var obj = this;
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200 || xmlHttp.status == 0) {
obj.Callback(xmlHttp.responseText);
}
}
}
xmlHttp.send(data);
}
}.Init(arguments);
}
})();
Then we need a class which we call EnhancedWebService
in .NET 3.5. DataContractJsonSerializer
makes the use of JSON easier. We also need a class we call if JSONHelper
has to Serialise and DeSerialise the JSON Object.
Here is the class of JSONHelper.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Json;
using System.IO;
namespace kuuy.Components
{
public class JSONHelper
{
public static string Serialize<T>(T obj)
{
string reVal = string.Empty;
using (MemoryStream m = new MemoryStream())
{
DataContractJsonSerializer serializer =
new DataContractJsonSerializer(obj.GetType());
serializer.WriteObject(m, obj);
reVal = Encoding.UTF8.GetString(m.ToArray());
m.Flush();
}
return reVal;
}
public static T Deserialize<T>(string json)
{
return Deserialize<T>(json, Activator.CreateInstance<T>().GetType());
}
public static T Deserialize<T>(string json, Type type)
{
T obj = Activator.CreateInstance<T>();
using (MemoryStream m = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
DataContractJsonSerializer serializer =
new DataContractJsonSerializer(type);
obj = (T)serializer.ReadObject(m);
m.Flush();
}
return obj;
}
}
}
Don't forget to add the reference of System.ServiceModel.Web
.
Here is the code of EnhancedWebService.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;
using System.IO;
using System.Web;
namespace kuuy.Components.Services
{
public class EnhancedWebService : System.Web.Services.WebService
{
public EnhancedWebService()
: base()
{
string ServiceMethodName = GetMethodName();
bool IsJSON = Context.Request.QueryString["out"] == "json";
if (IsJSON) InterceptJSONMethodRequest(ServiceMethodName);
}
private string GetMethodName()
{
return Context.Request.Url.Segments
[Context.Request.Url.Segments.Length - 1];
}
private void InterceptJSONMethodRequest(string ServiceMethodName)
{
JSONMethodAttribute JMA = GetMethodJSONMethodAttribute
(ServiceMethodName);
if (JMA == null)
{
Context.Response.Write("throw new Exception('The Web Service method " +
ServiceMethodName + " is not available " +
"as a JSON function. For more " +
"information contact " +
"the Web Service Administrators.');");
}
else
{
Type Service = this.GetType();
MethodInfo JSONMethod =
Service.GetMethod(ServiceMethodName);
if (JSONMethod == null) return;
ParameterInfo[] JSONMethodParameters = JSONMethod.GetParameters();
object[] CallParameters = new object[JSONMethodParameters.Length];
for (int i = 0; i < JSONMethodParameters.Length; i++)
{
ParameterInfo TargetParameter = JSONMethodParameters[i];
string RawParameter = HttpUtility.UrlDecode
(Context.Request.Form[TargetParameter.Name]);
if (RawParameter == null || RawParameter == "")
throw new Exception("Missing parameter " +
TargetParameter.Name + ".");
CallParameters[i] = JSONHelper.Deserialize<object>
(RawParameter, TargetParameter.ParameterType);
}
object JSONMethodReturnValue = JSONMethod.Invoke(this, CallParameters);
string SerializedReturnValue =
JSONHelper.Serialize<object>
(JSONMethodReturnValue);
Context.Response.Write(SerializedReturnValue);
}
Context.Response.Flush();
Context.Response.End();
}
private JSONMethodAttribute GetMethodJSONMethodAttribute
(string WebServiceMethodName)
{
MethodInfo ActiveMethod = this.GetType().GetMethod(WebServiceMethodName);
JSONMethodAttribute JMA = null;
if (ActiveMethod != null)
{
object[] Attributes = ActiveMethod.GetCustomAttributes(true);
foreach (object Attribute in Attributes)
{
if (Attribute.GetType() == typeof(JSONMethodAttribute))
{
JMA = (JSONMethodAttribute)Attribute;
}
}
}
return JMA;
}
}
public class JSONMethodAttribute : System.Attribute
{
public JSONMethodAttribute()
{
}
}
}
Now all the code is shown above. We need to make it work now. Here is my example:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml" >
<head>
<title></title>
<script src="js/kuuy.SOAPRequest.js" type="text/javascript"></script>
<script type="text/javascript">
var pattern = /webservice\.htm/gi;
var callback = function(o) {
alert(o);
}
function JSONRequest() {
var url = document.location.href.replace
(pattern, "WebService1.asmx/JSONService?out=json");
var request = new kuuy.SOAPRequest(url, callback);
request.AddParam("input", "88.88.88.88");
request.Open();
}
function SOAPRequest() {
var url = document.location.href.replace(pattern, "WebService1.asmx");
var method = "JSONService";
var request = new kuuy.SOAPRequest(url, method, callback);
request.AddParam("input", "88.88.88.88");
request.Open();
}
</script>
</head>
<body>
<input type="button" onclick="JSONRequest()" value="JOSN"/>
<input type="button" onclick="SOAPRequest()" value="SOAP"/>
</body>
</html>
You can download my full example. It's really simple and effective. Good luck!
Though I have no job and nobody will hire me, I never stop learning. I wish this will help you! Thanks for reading!
If you have any questions, you can email me at kuuy@hotmail.com.
History