好吧,这是我编写和使用的代码,但是您需要为自己的 wsdl 更改一些参数。反馈是appriciated。
此外,如果有人升级并将其制成博客文章,那会很棒(我没有博客)我想很多人会需要它,这可以节省我们项目的大量时间并整理东西。
顺便说一句,我在 Linqpad 中运行此代码。这就是为什么方法不是静态的,并且在 Main() 的最后一行有一个 object.Dump() 调用
void Main()
{
var svcUrl = "http://localhost:12345/MyService.svc";
var declaration = "declare var MyService: MyServiceClient;";
var koRef = "/// <reference path=\"../../Scripts/typings/knockout.mapping/knockout.mapping.d.ts" +
"\" />\r\n/// <reference path=\"../../Scripts/typings/knockout/knockout.d.ts\" />";
TypeScriptWebServiceAndKnockOutTypings(svcUrl, declaration, koRef).Dump();
}
string TypeScriptWebServiceAndKnockOutTypings(string svcUrl, string declaration, string koRef)
{
var outputPath = @"d:\output";
File.Delete(outputPath + ".cs");
File.Delete(outputPath + ".dll");
Process.Start(@"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\x64\svcutil.exe", " /language:cs /out:" + outputPath + ".cs " + svcUrl).WaitForExit();
Process.Start(@"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe", " /t:library /out:"+ outputPath + ".dll "+ outputPath + ".cs").WaitForExit();
var a = Assembly.LoadFile(outputPath + ".dll");
var sbEnums = new StringBuilder();
var sbClasses = new StringBuilder();
#region types conversions
var dictTypesNormal = new Dictionary<Type, string>();
dictTypesNormal.Add(typeof(Int32), "number");
dictTypesNormal.Add(typeof(UInt32), "number");
dictTypesNormal.Add(typeof(Int64), "number");
dictTypesNormal.Add(typeof(UInt64), "number");
dictTypesNormal.Add(typeof(float), "number");
dictTypesNormal.Add(typeof(double), "number");
dictTypesNormal.Add(typeof(bool), "bool");
dictTypesNormal.Add(typeof(string), "string");
dictTypesNormal.Add(typeof(Object), "any");
dictTypesNormal.Add(typeof(DateTime), "Date");
var dictTypesKnockout = new Dictionary<Type, string>();
dictTypesKnockout.Add(typeof(Int32), "KnockoutObservableNumber");
dictTypesKnockout.Add(typeof(UInt32), "KnockoutObservableNumber");
dictTypesKnockout.Add(typeof(Int64), "KnockoutObservableNumber");
dictTypesKnockout.Add(typeof(UInt64), "KnockoutObservableNumber");
dictTypesKnockout.Add(typeof(float), "KnockoutObservableNumber");
dictTypesKnockout.Add(typeof(double), "KnockoutObservableNumber");
dictTypesKnockout.Add(typeof(bool), "KnockoutObservableBool");
dictTypesKnockout.Add(typeof(string), "KnockoutObservableString");
dictTypesKnockout.Add(typeof(Object), "KnockoutObservableAny");
dictTypesKnockout.Add(typeof(DateTime), "KnockoutObservableDate");
var classNames = a.DefinedTypes.Where(t => !t.IsEnum).Select(t=>t.Name).ToList();
var enumNames = a.DefinedTypes.Where(t => t.IsEnum).Select(t=>t.Name).ToList();
#region get type name
Func<Type, string> getTypeNameNormal = t => {
if(dictTypesNormal.ContainsKey(t))
return dictTypesNormal[t];
if(classNames.Contains(t.Name.Replace("[]", "")))
return t.Name;
if(enumNames.Contains(t.Name.Replace("[]", "")))
return "Enum" + t.Name;
throw new Exception(string.Format("Unknown type [{0}]", t.Name));
};
Func<Type, string> getTypeNameKnockout = t => {
if(dictTypesKnockout.ContainsKey(t))
return dictTypesKnockout[t];
if(classNames.Contains(t.Name.Replace("[]", "")))
return t.Name + "_KnockoutMapped";
if(enumNames.Contains(t.Name.Replace("[]", "")))
return "KnockoutObservableEnum" + t.Name + "EnumMember";
throw new Exception(string.Format("Unknown type [{0}]", t.Name));
};
#endregion
#region convert field
Func<string, Type, string> convertFieldNormal = null; convertFieldNormal = (pName, f) => {
// void
if(f == typeof(void))
return "";
// array
if(f.IsArray)
return string.Format("{0}{1}[]", pName, convertFieldNormal("", f.GetElementType()));
// property
if(!f.IsGenericType)
return string.Format("{0}: {1}", pName, getTypeNameNormal(f));
// nullable
if(f.GetGenericTypeDefinition() == typeof(Nullable<>))
return string.Format("{0}: {1}", pName, getTypeNameNormal(f.GetGenericArguments()[0]));
// dictionaries
if(f.GetGenericTypeDefinition().ToString().Contains("Dictionary"))
return string.Format("{0}: {{ {1}; {2}; }}[]", pName, convertFieldNormal("Key", f.GetGenericArguments()[0]), convertFieldNormal("Value", f.GetGenericArguments()[1]));
throw new Exception(string.Format("Unknown generic type [{0}] for property {1}", f.Name, pName));
};
Func<string, Type, string> convertFieldKnockout = null; convertFieldKnockout = (pName, f) => {
// void
if(f == typeof(void))
return "";
// array
if(f.IsArray)
return string.Format("{0}{1}[]", pName, convertFieldKnockout("", f.GetElementType()));
// property
if(!f.IsGenericType)
return string.Format("{0}: {1}", pName, getTypeNameKnockout(f));
// nullable
if(f.GetGenericTypeDefinition() == typeof(Nullable<>))
return string.Format("{0}: {1}", pName, getTypeNameKnockout(f.GetGenericArguments()[0]));
// dictionaries
if(f.GetGenericTypeDefinition().ToString().Contains("Dictionary"))
return string.Format("{0}: {{ {1}; {2}; }}[]", pName, convertFieldKnockout("Key", f.GetGenericArguments()[0]), convertFieldKnockout("Value", f.GetGenericArguments()[1]));
throw new Exception(string.Format("Unknown generic type [{0}] for property {1}", f.Name, pName));
};
#endregion
#endregion
#region enums
foreach (var e in a.DefinedTypes.Where(t => t.IsEnum))
{
#region enum definition
sbEnums.AppendLine(string.Format("enum Enum{0} {{", e.Name));
sbEnums.AppendLine(string.Format("\t{0} = {1},", "Tümü", -1));
foreach (var v in Enum.GetValues(e))
{
sbEnums.AppendLine(string.Format("\t{0} = {1},", v.ToString(), (int)v));
}
sbEnums.AppendLine("}");
#endregion
#region knockout
sbEnums.AppendLine(string.Format(
@"interface KnockoutObservable{0} extends KnockoutObservableBase {{
(): {0};
(value: {0}): void;
subscribe(callback: (newValue: {0}) => void , target?: any, topic?: string): KnockoutSubscription;
notifySubscribers(valueToWrite: {0}, topic?: string);
}}", "Enum" + e.Name + "EnumMember"));
#endregion
#region enum member
sbEnums.AppendLine(string.Format(
@"class Enum{0}EnumMember {{
constructor(public Key: Enum{0}, public Value: string) {{ }};
public toString() {{ return this.Value }};
}}", e.Name));
#endregion
#region combobox definition
sbEnums.AppendLine(string.Format("var {0}s: Enum{0}EnumMember[] = [", e.Name));
sbEnums.AppendLine(string.Format("\t new Enum{0}EnumMember(Enum{0}.{1}, \"{1}\"),", e.Name, "Tümü"));
foreach (var v in Enum.GetValues(e))
{
sbEnums.AppendLine(string.Format("\t new Enum{0}EnumMember(Enum{0}.{1}, \"{1}\"),", e.Name, v.ToString()));
}
sbEnums.AppendLine("];");
#endregion
//public OnayDurumlari = ko.observable([{ Key: 3, Value: "Tümü" }, { Key: 0, Value: "Onay Bekliyor" }, { Key: 1, Value: "Onaylı" }, { Key: 2, Value: "Red" }]);
sbEnums.AppendLine();
}
#endregion
#region classes
#region find classes & methods
var classes = (from t in a.DefinedTypes
where t.IsEnum == false
let methods = (from m in t.GetMethods()
where !m.IsSpecialName
&& m.IsFinal
&& m.IsVirtual
&& m.IsHideBySig
&& m.IsSecurityCritical
&& !m.Name.EndsWith("Async")
select m)
where t.DeclaredProperties.Any()
|| methods.Any()
select new
{
t.Name,
t.DeclaredProperties,
methods,
});
#endregion
foreach (var t in classes)
{
#region interface definition
sbClasses.AppendLine(string.Format("{1} {0} {{", t.Name, t.DeclaredProperties.Any() ? "class" : "interface"));
foreach (var p in t.DeclaredProperties)
{
if(p.Name == "ExtensionData") continue;
var f = p.GetGetMethod().ReturnType;
sbClasses.AppendLine(string.Format("\t{0};", convertFieldNormal(p.Name, f)));
}
#region methods
foreach (var m in t.methods)
{
sbClasses.AppendLine(string.Format("\t{0}({1}Success: ({2}) => void, Fail?: (err: Sys$Net$WebServiceError) => void ) : void;",
m.Name,
string.Concat(m.GetParameters().Select(p => convertFieldNormal(p.Name, p.ParameterType) + ", ")),
convertFieldNormal("result", m.ReturnType)));
}
#endregion
sbClasses.AppendLine("}");
#endregion
#region knockout
if(t.DeclaredProperties.Any())
{
sbClasses.AppendLine(string.Format(@"
interface KnockoutObservable{0} extends KnockoutObservableBase {{
(): {0};
(value: {0}): void;
subscribe(callback: (newValue: {0}) => void , target?: any, topic?: string): KnockoutSubscription;
notifySubscribers(valueToWrite: {0}, topic?: string);
}}", t.Name));
//
// sbClasses.AppendLine(string.Format(@"
// interface KnockoutObservableStatic {{
// (value: {0}): KnockoutObservable{0};
// new (value: {0}): KnockoutObservable{0};
// }}", t.Name));
#region KnockoutObservableArray
sbClasses.AppendLine(string.Format(
@"interface {0}_KnockoutObservableArray extends KnockoutObservableArrayFunctions {{
(): {0}_KnockoutMapped[];
(value: {0}_KnockoutMapped[]): void;
subscribe(callback: (newValue: {0}_KnockoutMapped[]) => void, target?:any, topic?: string): KnockoutSubscription;
notifySubscribers(valueToWrite: {0}_KnockoutMapped[], topic?: string);
}}", t.Name));
#endregion
#region _KnockoutMapped
sbClasses.AppendLine(string.Format("interface {0}_KnockoutMapped {{", t.Name));
foreach (var p in t.DeclaredProperties)
{
if(p.Name == "ExtensionData") continue;
var f = p.GetGetMethod().ReturnType;
sbClasses.AppendLine(string.Format("\t{0};", convertFieldKnockout(p.Name, f)));
}
sbClasses.AppendLine("}");
#endregion
}
#endregion
sbClasses.AppendLine();
}
#endregion
#region knockout
var sbKnockout = new StringBuilder();
#region mapper
sbKnockout.AppendLine("module Mapper {");
classes.Where(c=>c.DeclaredProperties.Any()).ToList().ForEach(c=>{
sbKnockout.AppendLine(string.Format("\texport function fromJs_{0}(r : {0}) : {0}_KnockoutMapped {{return ko.mapping.fromJS(r);}}", c.Name));
sbKnockout.AppendLine(string.Format("\texport function toJs_{0}(r : {0}_KnockoutMapped) : {0} {{return ko.mapping.toJS(r);}}", c.Name));
sbKnockout.AppendLine(string.Format("\texport function fromJsArray_{0}(r : {0}[]) : {0}_KnockoutMapped[] {{return r.map(k => ko.mapping.fromJS(k));}}", c.Name));
sbKnockout.AppendLine(string.Format("\texport function toJsArray_{0}(r : {0}_KnockoutMapped[]) : {0}[] {{return r.map(k => ko.mapping.toJS(k));}}", c.Name));
});
sbKnockout.AppendLine("}");
sbKnockout.AppendLine();
#endregion
#region knockout definitions
sbKnockout.AppendLine("declare var ko;");
dictTypesKnockout.Select(k=>k.Value).Distinct().ToList().ForEach(k=>{
sbKnockout.AppendLine(string.Format("interface {0} {{}}", k));
});
sbKnockout.AppendLine("interface KnockoutSubscription {}");
sbKnockout.AppendLine("interface KnockoutObservableArrayFunctions {}");
sbKnockout.AppendLine();
#endregion
#endregion
return koRef
+ "interface Sys$Net$WebServiceError {_timedOut: bool;_message: string;_stackTrace: string;_exceptionType: string;_errorObject: {ExceptionDetail: {HelpLink: any; InnerException: any; Message: string; StackTrace: string;Type: string;};ExceptionType: string;Message: string;StackTrace: string;};}\r\n\r\n"
+ sbEnums.ToString()
+ sbClasses.ToString()
+ sbKnockout
+ declaration;
}