如何使用 JS 通过 POST 同时调用 SOAP 和 JSON Web 服务
WebService 同时支持 SOAP 和 JSON

引言
这里提供一个完整的示例,展示如何使用 JS 通过 Post 方法调用 WebService,同时支持 SOAP 和 JSON。
背景
现在几乎每个人都在谈论 Ajax 和 WebService。我也尝试了,并编写了一个 JS 来完成这项工作!阅读我的文章后,你会发现事情其实很简单!
我的示例有一些不同之处。它确实可以在 Internet Explorer 6、Internet Explorer 7、Opera 和 Netscape 中正常工作。你会发现,在 Firefox3 中,它不支持同步函数来调用 WebService。我还发现我们无法在 Internet Explorer 6 中创建超过一个 xmlhttprequest
对象。我已经修复了这个问题。它运行良好,但不支持 Internet Explorer 5,因为它不支持 push()
函数。我还没有尝试在 Internet Explorer 5 中测试它。
你可能需要知道,xmlhttprequest
不支持跨域 WebService。
Using the Code
这里是 kuuy.SoapRequest.js 文件
(function() {
//If you read the oriented Ajax JS, it's used to register a namespace
var Namespace = {
Register: function(_Name) {
var o = window;
var x = false;
for (var a = _Name.split("."); a.length > 0; ) {
//remove the top element
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;
//XMLparser,we call it ajax activeobject
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~!");
}
}
})();
//Parameter
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);
}
//SOAPRequest,We Instanced it,and then call the method Open
kuuy.SOAPRequest = function() {
return {
URL: null, //url
Method: null, //the method we calling
Params: null, //parameters
Callback: null, //callback a function
WSDLS: null, //webservice descriptions
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()//add a parameter
{
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 the request
Open: function() {
var obj = this;
if (this.WSDLS) {
var wsdl = this.WSDLS[this.URL];
if (!wsdl) {
xmlHttp.open
("GET", this.URL + "?wsdl", true); //async request
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200 || xmlHttp.status == 0) {
//the soap request
(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); //asnyc request
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;
//method we calling
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); //asyc request
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);
}
})();
然后我们需要一个在 .NET 3.5 中名为 EnhancedWebService
的类。DataContractJsonSerializer
使得使用 JSON 更加容易。我们还需要一个名为 JSONHelper
的类,用于序列化和反序列化 JSON 对象。
这里是 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
{
//Serialize
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;
}
//Deserialize
public static T Deserialize<T>(string json)
{
return Deserialize<T>(json, Activator.CreateInstance<T>().GetType());
}
//Deserialize(Dynamic Type)
public static T Deserialize<T>(string json, Type type)
{
T obj = Activator.CreateInstance<T>();//Instance
using (MemoryStream m = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
DataContractJsonSerializer serializer =
new DataContractJsonSerializer(type);
obj = (T)serializer.ReadObject(m);
m.Flush();
}
return obj;
}
}
}
别忘了添加 System.ServiceModel.Web
的引用。
这里是 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
{
//WebService Extension
public class EnhancedWebService : System.Web.Services.WebService
{
public EnhancedWebService()
: base() //Base Construct
{
string ServiceMethodName = GetMethodName();
bool IsJSON = Context.Request.QueryString["out"] == "json";
if (IsJSON) InterceptJSONMethodRequest(ServiceMethodName);
}
private string GetMethodName()//Get the method we are calling
{
return Context.Request.Url.Segments
[Context.Request.Url.Segments.Length - 1];//URL Segment('\')
}
private void InterceptJSONMethodRequest(string ServiceMethodName)
{
JSONMethodAttribute JMA = GetMethodJSONMethodAttribute
(ServiceMethodName);//Description Class
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
{
//ToDo: deserialize parameters, call target method,
// deserialize and write return value
Type Service = this.GetType();
MethodInfo JSONMethod =
Service.GetMethod(ServiceMethodName);//Get Parameters
if (JSONMethod == null) return;
//Parameters
ParameterInfo[] JSONMethodParameters = JSONMethod.GetParameters();
object[] CallParameters = new object[JSONMethodParameters.Length];
for (int i = 0; i < JSONMethodParameters.Length; i++)
{
//Parameter
ParameterInfo TargetParameter = JSONMethodParameters[i];
string RawParameter = HttpUtility.UrlDecode
(Context.Request.Form[TargetParameter.Name]);//Get Value
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);//Return JSON Object
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;
}
}
//WebService Description
public class JSONMethodAttribute : System.Attribute
{
public JSONMethodAttribute()
{
}
}
}
现在所有代码都已显示在上方。我们需要让它工作起来。这是我的示例
<!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(); //Send SOAP Request
}
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(); //Send SOAP Request
}
</script>
</head>
<body>
<input type="button" onclick="JSONRequest()" value="JOSN"/>
<input type="button" onclick="SOAPRequest()" value="SOAP"/>
</body>
</html>
你可以下载我的完整示例。它非常简单有效。祝你好运!
虽然我没有工作,也没有人会雇佣我,但我从未停止学习。我希望这能帮助你!感谢阅读!
如果你有任何问题,可以发送邮件至 kuuy@hotmail.com。
历史
- 2009-04-07 初始发布