專案需動態指定 WebService URL,採用「執行時下載 WSDL → 動態編譯組件 → 反射呼叫」方案。實測發現動態呼叫耗時 1.29 秒,靜態代理僅 0.43 秒,效能差距近 3 倍。本文分析根因並探討優化方向。
public object InvokeWebservice(string url, string @namespace, string classname, string methodname, object[] args)
{
WebClient wc = new WebClient();
Stream stream = wc.OpenRead(url + "?WSDL");
ServiceDescription sd = ServiceDescription.Read(stream);
ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
sdi.AddServiceDescription(sd, "", "");
CodeNamespace cn = new CodeNamespace(@namespace);
CodeCompileUnit ccu = new CodeCompileUnit();
ccu.Namespaces.Add(cn);
sdi.Import(cn, ccu);
CSharpCodeProvider csc = new CSharpCodeProvider();
ICodeCompiler icc = csc.CreateCompiler();
CompilerParameters cplist = new CompilerParameters();
cplist.GenerateInMemory = true;
cplist.ReferencedAssemblies.AddRange(new[] { "System.dll", "System.Xml.dll", "System.Web.Services.dll", "System.Data.dll" });
CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);
if (cr.Errors.HasErrors) throw new Exception(/* 錯誤訊息 */);
Assembly assembly = cr.CompiledAssembly;
Type t = assembly.GetType(@namespace + "." + classname, true, true);
object obj = Activator.CreateInstance(t);
MethodInfo mi = t.GetMethod(methodname);
return mi.Invoke(obj, args);
}
ServiceDescriptionImporter 解析 WSDL、建構 CodeDom 樹。CSharpCodeProvider 編譯記憶體組件(含語法分析、IL 生成、JIT)。Activator.CreateInstance、MethodInfo.Invoke 晚繫結開銷。靜態代理僅有一次性 JIT 開銷,後續呼叫為直接虛擬方法調用。
// 專案加入服務參考生成靜態代理類別 MyServiceClient
var client = new MyServiceClient();
client.Endpoint.Address = new EndpointAddress(dynamicUrl); // 執行時指定 URL
client.DoWork();
前提:所有目標服務契約(介面、資料合約)完全一致,僅端點位址不同。
Assembly 或 ChannelFactory<T>。var binding = new BasicHttpBinding();
var address = new EndpointAddress(dynamicUrl);
var factory = new ChannelFactory(binding, address);
IMyService proxy = factory.CreateChannel();
proxy.DoWork();
((IClientChannel)proxy).Close();
無需 WSDL 下載與編譯,直接依共用介面組件建立通道,效能接近靜態代理。
動態 WebService 呼叫的效能代價主要在「WSDL 下載 → 編譯」管線。若契約固定,強烈建議使用靜態代理 + 動態 Endpoint Address 或 ChannelFactory<T> 方案,兼具彈性與高效能。唯有契約本身動態變化時,才需完整動態編譯流程。