Я бы воспользовался xml/xsl. Взял бы xml-контракт службы (его wsdl), вытащил из него список методов и трансформировал в js.
Вот примерно как я это делаю для своих сервисов (не wcf).
C помощью специальной утилиты формирую xml-представление необходимых классов (этакий самопальный wsdl (фрагмент), у тебя он готовый):
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
<Classes xmlns="http://tempuri.org/app">
<Banners FileName="Banners.ts" EditEntity="tblBanner" ListEntity="nmlBanners" xmlns="">
<Attrs>
<ExtModel>_ModelTables.tblBanner, _ModelTables.nmlBanners</ExtModel>
</Attrs>
<Implements>
<IBanner />
</Implements>
<Methods>
<EditRecord Type="System.Void" Name="EditRecord">
<ID Type="Integer" />
</EditRecord>
<SaveRecord Type="BannersManager.tblBanner" Name="SaveRecord">
<ID Type="Integer" />
<mObj Type="BannersManager.tblBanner" />
</SaveRecord>
</Methods>
<Enums />
<Bases>
<_BasicHandler />
</Bases>
</Banners>
</Classes>
Применяю к нему примерно такой xsl (тоже фрагмент):
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
<xsl:apply-templates select="Methods/*"/>
<xsl:template match="Methods/*">
<xsl:if test="not(preceding-sibling::*/@Name=@Name)">
export var <xsl:value-of select="name()"/>
<xsl:text> = {url:objName + ".ashx/</xsl:text>
<xsl:value-of select="name()"/>",run: function(<xsl:apply-templates select="*"/>
<xsl:text>callback?:Function):void{MakeQuery(</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>.url,callback,arguments)}}</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="Methods/*/*">
<xsl:value-of select="name()"/><xsl:if test="@Default">?</xsl:if>:<xsl:apply-templates select ="@Type"/><xsl:text>,</xsl:text>
</xsl:template>
На выходе у меня такой модуль (полнофункциональный, генерирую не JS, а TS)
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
module BannersManager{
var sNameSpace: string = "BannersManagerNS";
export var Name: string = sNameSpace;
// callback
// function(xhr:XmlHttpRequest){}
export var errorResponseCallback: Function;
// callback
// function(error:string, responseText:string){}
export var errorParseCallback: Function;
// callback
// function(html:string){}
export var errorCallback: Function;
export var baseURL: string = "";
export var blocker: string = "blocker";
export module Banners {
var objName:string="Banners";
// tblBanner / nmlBanners /
export interface tblBanner {ID:number;Name:string;Width:number;Height:number;LastUpdate:any;FileSize:number;}
export var EditRecord = {url:objName + ".ashx/EditRecord",run: function(ID:number,callback?:Function):void{MakeQuery(EditRecord.url,callback,arguments)}}
export var SaveRecord = {url:objName + ".ashx/SaveRecord",run: function(ID:number,mObj:tblBanner,callback?:Function):void{MakeQuery(SaveRecord.url,callback,arguments)}}
}
Function.prototype["argumentNames"] = function() {
var ret = { func: null, argNames: null };
ret.argNames = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1].replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '').replace(/\s+/g, '').split(',');
var fn = this.toString().match(/^[\s\(]*function[^\w]+([\w]+)[^\w]*\(/);
if(fn)ret.func = fn[1];
return ret;
}
function NewQuery(method: string, url: string, callback: Function, data?: any): XMLHttpRequest {
var xhr: XMLHttpRequest;
if (XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (ActiveXObject) {
xhr = new ActiveXObject("MSXML2.XMLHTTP");
} else {
alert("Your browser doesn't support XmlHttpRequest!");
return;
}
xhr.open(method, url, true);
xhr.setRequestHeader("X-Requested-With", "XmlHttpRequest");
xhr.setRequestHeader("Accept", "text/json");
if (method == 'post') xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var b = document.getElementById(blocker);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if(b)b.style.display = "none";
if (xhr.status == 200) {
try {
var response: any = JSON.parse(xhr.responseText);
} catch (e) {
if (errorParseCallback)
errorParseCallback(e, xhr.responseText);
else
callback(xhr.responseText);
return;
}
callback(response);
} else if (xhr.status == 500) {
if (errorResponseCallback)
errorResponseCallback(xhr)
else
alert(xhr.responseText);
} else {
if (errorCallback)
errorCallback(xhr.responseText)
else
alert(xhr.status.toString());
}
}
}
if(b)b.style.display = "block";
if (data) { xhr.send(data) } else { xhr.send() };
return xhr;
}
function MakeQuery(methodUrl: string, callback: Function, Args: any): void {
var para = Args.callee.argumentNames();
var queryStr: string = baseURL + methodUrl + "?", form: string = "", arg: string;
for (var x = 0; x < Args.length - 1; x++) {
if(Args[x]){
if (typeof Args[x] == "object") {
form += para.argNames[x] + "=" + encodeURIComponent(JSON.stringify(Args[x])) + "&";
} else {
queryStr += para.argNames[x] + "=" + encodeURIComponent(Args[x]) + "&";
}
}
}
NewQuery(form.length ? "post" : "get", queryStr, callback, form);
}
}
Использование модуля:
1.
2.
3.
4.
5.
6.
7.
function ShowDetails(id: number) {
var $bl = $(".blocker").css("display", "table-cell");
BannersManager.Banners.EditRecord.run(id, function (responseText) {
var $bnr = $("#bnr_" + id).remove();
$(responseText).appendTo($bl);
})
}
В этой схеме тебе нужно 1) переписать функцию NewQuery так, чтобы она умела делать soap-запросы, формируя соответствующий xml. Не помню формат запросов, если в нем участвуют типы переменных, то при генерации методов надо как-то связывать с ними типы аргументов, чтобы было что вставить. 2) переписать xsl, заточив под wsdl.
Остальное можно оставить как есть.
Идея ясна?