在C#程序中,若要调用WebService,一般是采用"添加Web引用"的方式来实现的。但如果此WebService的URL是在程序运行过程中才能获得的,那怎么办呢?那就必须是"动态"调用这个WebService了。
?
网上有不少关于这方面的例子,总结了一下,主要有两种:(1)每次都动态调用,(2)将WebService生成为一个本地的DLL,生成客户端的实例。
第一种方法:
我把它放到一个叫WebServiceHelper.cs的类里面了。
- ??
- ??????????
- ??????????
- ///?<param?name="url">WebService地址</param>???
- ///?<param?name="classname">类名</param>???
- ///?<param?name="methodname">方法名(模块名)</param>???
- ///?<param?name="args">参数列表</param>???
- ///?<returns>object</returns>???
- ????????public?static?object?InvokeWebService(string?url,?string?classname,153); background-color:inherit; font-weight:bold">string?methodname,153); background-color:inherit; font-weight:bold">object[]?args)??
- ????????{??
- ????????????string?@namespace?=?"ServiceBase.WebService.DynamicWebLoad";??
- ????????????if?(classname?==?null?||?classname?==?"")??
- ????????????{??
- ????????????????classname?=?WebServiceHelper.GetClassName(url);??
- ????????????}??
- ??????????????
- ????????????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.GenerateExecutable?=?false;??
- ????????????cplist.GenerateInMemory?=?true;??
- ????????????cplist.ReferencedAssemblies.Add("System.dll");??
- ????????????cplist.ReferencedAssemblies.Add("System.XML.dll");??
- ????????????cplist.ReferencedAssemblies.Add("System.Web.Services.dll");??
- ????????????cplist.ReferencedAssemblies.Add("System.Data.dll");??
- //编译代理类???
- ????????????CompilerResults?cr?=?icc.CompileAssemblyFromDom(cplist,153); background-color:inherit; font-weight:bold">if?(true?==?cr.Errors.HasErrors)??
- ????????????{??
- ????????????????System.Text.StringBuilder?sb?=?new?StringBuilder();??
- ????????????????foreach?(CompilerError?ce?in?cr.Errors)??
- ????????????????{??
- ????????????????????sb.Append(ce.ToString());??
- ????????????????????sb.Append(System.Environment.NewLine);??
- ????????????????}??
- ????????????????throw?new?Exception(sb.ToString());??
- ????????????}??
- //生成代理实例,并调用方法???
- ????????????System.Reflection.Assembly?assembly?=?cr.CompiledAssembly;??
- ????????????Type?t?=?assembly.GetType(@namespace?+?"."?+?classname,153); background-color:inherit; font-weight:bold">true,153); background-color:inherit; font-weight:bold">true);??
- object?obj?=?Activator.CreateInstance(t);??
- ????????????System.Reflection.MethodInfo?mi?=?t.GetMethod(methodname);??
- return?mi.Invoke(obj,?args);??
- ????????}??
- ??
- private?string?GetClassName(string?url)??
- string[]?parts?=?url.Split('/');??
- string[]?pps?=?parts[parts.Length?-?1].Split('.');??
- return?pps[0];??
- ????????}??
举个使用它的例子:
copy
object[]?args?=?new?object[1];??
- ????????????args.SetValue("cyy_JS",?0);??
- ????????????DataTable?dt?=?WebServiceHelper.InvokeWebService("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx",?"GetUserTreeListData",?args)?as?DataTable;??
恩~有点麻烦,这意味着每次我都要把想调用的函数的参数组织成一个object[]才行,且每次调用InvokeWebService都是在内存中创建动态程序集,效率极低。则次种方法绝对没有直接用“实例名.方法名(参数列表)”来的舒服。
第二种方法:
为了提高效率,希望不要每次都创建这么一个动态程序集,那么就要把这个程序集保存在本地,使用的时候调用这个本地的DLL即可。
首先要调用:WebServiceHelper.CreateWebServiceDLL(); 用来在Debug目录下生成dll。这个函数的代码如下:
copy
void?CreateWebServiceDLL()??
- //?1.?使用?WebClient?下载?WSDL?信息。??
- ????????????WebClient?web?=?new?WebClient();??
- ????????????Stream?stream?=?web.OpenRead("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx?WSDL");??
- //?2.?创建和格式化?WSDL?文档。??
- ????????????ServiceDescription?description?=?ServiceDescription.Read(stream);??
- //?3.?创建客户端代理代理类。??
- ????????????ServiceDescriptionImporter?importer?=?new?ServiceDescriptionImporter();??
- ????????????importer.ProtocolName?=?"Soap";???
- ????????????importer.Style?=?ServiceDescriptionImportStyle.Client;???
- ????????????importer.CodeGenerationOptions?=?CodeGenerationOptions.GenerateProperties?|?CodeGenerationOptions.GenerateNewAsync;??
- ????????????importer.AddServiceDescription(description,?null,153); background-color:inherit; font-weight:bold">null);???
- //?4.?使用?CodeDom?编译客户端代理类。??
- ????????????CodeNamespace?nmspace?=?new?CodeNamespace();??????????
- ????????????CodeCompileUnit?unit?=? ????????????unit.Namespaces.Add(nmspace);??
- ????????????ServiceDescriptionImportWarnings?warning?=?importer.Import(nmspace,?unit);??
- ????????????CodeDomProvider?provider?=?CodeDomProvider.CreateProvider("CSharp");??
- ????????????CompilerParameters?parameter?=? ????????????parameter.GenerateExecutable?=? ????????????parameter.OutputAssembly?=?"DBMS_Service.dll";????
- ????????????parameter.ReferencedAssemblies.Add("System.dll");??
- ????????????parameter.ReferencedAssemblies.Add("System.XML.dll");??
- ????????????parameter.ReferencedAssemblies.Add("System.Web.Services.dll");??
- ????????????parameter.ReferencedAssemblies.Add("System.Data.dll");??
- ????????????CompilerResults?result?=?provider.CompileAssemblyFromDom(parameter,?unit);??
- if?(result.Errors.HasErrors)??
- ??????????????????
- in?result.Errors)??
- ????????}??
下面举个使用的例子:
copy
Assembly?asm?=?Assembly.LoadFrom("DBMS_Service.dll");??
- ????????????Type?t?=?asm.GetType("DBMS_Service");??
- object?o?=?Activator.CreateInstance(t);??
- ????????????MethodInfo?method?=?t.GetMethod("GetUserTreeListData");??
- ????????????DataTable?dt?=?method.Invoke(o,?args)? 这种方法的好处就是只用创建一次程序集,但缺点仍是调用函数的方式比较麻烦。
第二种方法升级版:
哈哈,这个是我自创的。目的就是为了解决:只创建一次DLL;以类似“实例名.方法名(参数列表)”的方式来调用函数;以这个DLL为模板,若WebService的内容有更新时,可同时更新这个本地的DLL。
代码如下:
copy
///?<summary> ??
- ///?根据WebService的URL,生成一个本地的dll,放在C盘下面,例如:C:|DBMS_WebService.dll??
- ///?创建人:程媛媛?创建时间:2010-6-21??
- ///?</summary>??
- ///?<param?name="url">WebService的UR</param>??
- ///?<returns></returns>??
- void?CreateWebServiceDLL(string?classname?=?WebServiceHelper.GetClassName(url);??
- ????????????Stream?stream?=?web.OpenRead(url?+?"?WSDL");??
- namespace);?
- 首先调用CreateWebServiceDLL("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx")来生成“C:/DBMS_WebService.dll”;
接着,把这个DLL添加到工程的“引用”当中。
也许你会问,为什么不直接把DBMS_WebService.dll放在debug下?答案是,当把DBMS_WebService.dll添加为引用时,若在程序运行过程中要更新(包括删了重新创建)它,则会报错。尝试了几次,被我发现,是不能放在Debug下的,其他的任何路径都可以,例如bin目录下都可以,具体原因我不知道...
既然都把DBMS_WebService.dll添加为引用了,那么便可以先声明它了:
copy
static?ServiceBase.WebService.DynamicWebLoad.DBMS_Service?pDBMS_Service;??
注意:“public static ServiceBase.WebService.DynamicWebLoad.DBMS_Service”是我们调用CreateWebServiceDLL("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx")的过程中自定的表空间名。
接下来的事就是,需要一个函数,用来以此DBMS_WebService.dll为模板,用传入的URL来重新生成并覆盖这个DLL,并且,为了省事,直接返回一个ServiceBase.WebService.DynamicWebLoad.DBMS_Service的实例。
copy
??
- object?GetWebServiceInstance( ????????????parameter.OutputAssembly?=?"C://DBMS_Service.dll";?//?可以指定你所需的任何文件名。??
- ??????????????
- ????????????parameter.ReferencedAssemblies.Add("System.dll");??
- ????????????parameter.ReferencedAssemblies.Add("System.XML.dll");??
- ????????????parameter.ReferencedAssemblies.Add("System.Web.Services.dll");??
- ????????????parameter.ReferencedAssemblies.Add("System.Data.dll");??
- ????????????CompilerResults?result?=?provider.CompileAssemblyFromDom(parameter,153); background-color:inherit; font-weight:bold">if?(result.Errors.HasErrors)??
- ??????????????????
- ????????????????System.Text.StringBuilder?sb?=?new?StringBuilder();??
- in?result.Errors)??
- ????????????????{??
- ????????????????????sb.Append(ce.ToString());??
- ????????????????????sb.Append(System.Environment.NewLine);??
- ????????????????}??
- new?Exception(sb.ToString());??
- //生成代理实例??
- ????????????System.Reflection.Assembly?assembly?=?Assembly.Load("DBMS_Service");??
- ????????????Type?t?=?assembly.GetType(@true);??
- object?obj?=?Activator.CreateInstance(t);??
- return?obj;??
- 一切准备就绪,在主程序中这样使用它:
copy
object?o?=?WebServiceHelper.GetWebServiceInstance(this.WebServiceURL);??
- pDBMS_Service?=?o?as?ServiceBase.WebService.DynamicWebLoad.DBMS_Service;??
- DataTable?dt?=?pDBMS_Service.GetUserTreeListData(this.UserName);??
?
终于写完了。。。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|