您好,登錄后才能下訂單哦!
對于這個問題,很很早以前就遇到了,當時并不理解。前段時間看了一下動態代理,對這個問題有了一些了解。
對于一般的webservice,可以通過添加web引用實現調用。但這樣的缺點就是不夠靈活,當webservice地址發生變化時需要重新添加引用,重新編譯。這種缺點還稍微可以接受的。我遇到的應用場景是,程序運行之前無法知道webservice的地址,因為地址都存放于數據庫中,使用時需要動態的調用。這樣通過添加引用基本不可能實現,所以采用上述方法實現。
在采用這種方法時,首先遇到的問題就是:如何構造的代理類?
類似于java中JDK提供的有編譯源文件的接口,.net也提供的有相關的類似的我們能夠動態的生成源碼并進行編譯,從而動態的生成代理類。(當然不排除大牛通過解析語法規則直接生成二進制文件,而無需調用編譯接口的。)
我們可以采用類似于下面的方法來動態的生成要編譯的源碼。
private CodeCompileUnit GetServiceCompileUnit(string webServiceUrl)
{
WebClient client = new WebClient();
Stream stream = client.OpenRead(webServiceUrl);
//從這個url指向的的是一個xml文件,里面包含了該service的全部信息。
//進而通過解析xml文件從而可以生成要編譯的源碼。有興趣的可以看一下xml的內容
ServiceDescription description = ServiceDescription.Read(stream); ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); importer.ProtocolName = "Soap";//使用的協議
importer.Style = ServiceDescriptionImportStyle.Client;
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
importer.AddServiceDescription(description, "", "");
CodeNamespace nmspace = new CodeNamespace();
nmspace.Name = "WebService";//生成類的名空間,可以根據需求指定
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nmspace);
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
return unit;
}
Unit返回的就是要進行編譯的東西了。
下一步及時進行編譯了。根據需求設置相關的編譯參數后,就就可以進行編譯了。就像下邊這樣。
private CompilerResults Compile(CodeCompileUnit unit)
{
CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
// cp.OutputAssembly = "D:\\Test.dll";這里也可以將變異的結果輸出到dll文件中,從而可以查看編譯的的結果。有興趣的自己看一下。
compilerParameters.ReferencedAssemblies.Add("System.dll");
compilerParameters.ReferencedAssemblies.Add("System.XML.dll");
compilerParameters.ReferencedAssemblies.Add("System.Web.Services.dll");
compilerParameters.ReferencedAssemblies.Add("System.Data.dll");
CompilerResults compilerResults = codeDomProvider.CompileAssemblyFromDom(compilerParameters, unit);
if (compilerResults.Errors.HasErrors)
{
string errors = "";
foreach (var item in compilerResults.Errors)
{
errors += item.ToString() + Environment.NewLine;
}
throw new Exception("Compile error:" + errors);
}
return compilerResults;
}
有了編譯的結果,已經生成了代理類,下一步要做的就是將這個代理類加載到內存當中。
Assembly asm = result.CompiledAssembly;
object obj = asm.CreateInstance("WebService." + proxy._className);
這樣就將代理類加載到了內存當中,并且長生了一個實例,將這個實例返回就可以根據他來調用所需的方法了。當然調用方法時可能還是要用到反射,因為已知的可能僅僅只有方法名和它所需的參數。
更多詳細內容請查看本文源碼。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。