动态调用web服务

动态调用web服务

Technorati 标签:

通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务。这样是使工作简单了,但是却和提供Web服务的URL、方法名、参数绑定在一起了,这是VS.NET自动为我们生成Web服务代理的限制。如果哪一天发布Web服务的URL改变了,则我们需要重新让VS.NET生成代理,并重新编译。在某些情况下,这可能是不能忍受的,我们需要动态调用WebService的能力。比如我们可以把Web服务的URL保存在配置文件中,这样,当服务URL改变时,只需要修改配置文件就可以了。
说了这么多,实际上我们要实现这样的功能:

public static object InvokeWebService(string url, string methodname, object[] args)

其中,url是Web服务的地址,methodname是要调用服务方法名,args是要调用Web服务所需的参数,返回值就是web服务返回的结果了。
要实现这样的功能,你需要这几个方面的技能:反射、CodeDom、编程使用C#编译器、WebService。在了解这些知识后,就可以容易的实现web服务的动态调用了:

#region InvokeWebService
//动态调用web服务
public static object InvokeWebService(string url, string methodname, object[] args)
{
return WebServiceHelper.InvokeWebService(url ,null ,methodname ,args) ;
}
public static object InvokeWebService(string url, string classname, string methodname, object[] args)
{
string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling" ;
if((classname == null) ||(classname == ""))
{
classname = WebServiceHelper.GetWsClassName(url) ;
}
try
{
//获取WSDL
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, ccu);
if(true == cr.Errors.HasErrors)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach(System.CodeDom.Compiler.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,true,true);
object obj = Activator.CreateInstance(t);
System.Reflection.MethodInfo mi = t.GetMethod(methodname);
return mi.Invoke(obj,args);
}
catch(Exception ex)
{
throw new Exception(ex.InnerException.Message,new Exception(ex.InnerException.StackTrace));
}
}
private static string GetWsClassName(string wsUrl)
{
string[] parts = wsUrl.Split('/') ;
string[] pps = parts[parts.Length-1].Split('.') ;
return pps[0] ;
}
#endregion

上面的注释已经很好的说明了各代码段的功能,下面给个例子看看,这个例子是通过访问http://www.webservicex.net/globalweather.asmx 服务来获取各大城市的天气状况。

string url = "http://www.webservicex.net/globalweather.asmx" ;
string[] args = new string[2] ;
args[0] = this.textBox_CityName.Text ;
args[1] = "China" ;
object result = WebServiceHelper.InvokeWebService(url ,"GetWeather" ,args) ;
this.label_Result.Text = result.ToString() ;

上述的例子中,调用web服务使用了两个参数,第一个是城市的名字,第二个是国家的名字,Web服务返回的是XML文档,可以从其中解析出温度、风力等天气情况。
最后说一下,C#虽然仍属于静态语言之列,但是其动态能力也是很强大的,不信,你可以看看Spring.net的AOP实现,这种“无侵入”的AOP实现比通常的.NET声明式AOP实现(一般是通过AOP Attribute)要漂亮的多。

分类: C#专栏

绿色通道:好文要顶关注我收藏该文与我联系

动态调用web服务

zhuweisky
关注 - 8
粉丝 - 165

荣誉:推荐博客

+加关注

0

0

(请您对文章做出评价)

« 博主前一篇:使用 EmptyClass 避免条件判断
» 博主后一篇:分页管理器实现
« 首页前一篇:使用 EmptyClass 避免条件判断
» 首页后一篇:构件技术,应用软件行业的未来

posted @ 2005-12-07 13:25 zhuweisky 阅读(8612) 评论(14)编辑 收藏

动态调用web服务

发表评论

1988944

回复 引用

#1楼2005-12-07 13:35 | zyhjolly[未注册用户]

ws的url本来就可以随时修改的啊
只是方法的参数是固定的,当然也可以定义的时候就用个数组或列表来表示参数是动态增加的

回复 引用 查看

#2楼2005-12-07 18:32 | 双鱼座

hehe,首先我不觉得你这个就算动态了。真正的动态应该是直接获得wsdl来调用,次一点的动态知道参数格式,但URL和方法名不定。你这个基本上已经知道方法名了,就算是静态了,只不过是在运行时导出代理(平常都是由wsdl工具或其它工具代劳,都是设计时的)。其次,CodeDOM其实不适合运行时使用,.net的运行时动态代码方案是推荐Emit的,两者在功能、性能、对环境的依赖上有着很大的区别。最后,语言的静态或是动态与否与运行时代码生成能力无关,而是表示在类型的静态或者动态能力。事实上,动态生成代码(无论是CodeDOM还是Emit)都是CLI实现的,与C#并无关系。
这是我的动态Web实现,供你参考:http://barton131420.cnblogs.com/archive/2005/07/11/190518.html

回复 引用

#3楼2005-12-07 20:18 | gst[未注册用户]

没这么复杂吧。添加webservice的引用后改为“动态”地址,系统自动产生的..exe.config,直接修改就可以了。系统有一个对cofig文件修改的接口就行了。
这样不满足要求吗?

回复 引用

#4楼2006-02-21 11:33 | neat[未注册用户]

上述动态调用方法是否也可以适用于Java开发的webservice?本地是用.net开发的webservice向调用对方用java开发的webservice,根据上述方法试了一下,到了这一句时出现异常
Type t = assembly.GetType(@namespace+"."+classname,true,true);
我怀疑是由于对方提供的namespace不正确,不知道真的是这样的吗?还是通过这种方法根本就不能调用java的Webservice?

回复 引用

#5楼2006-02-21 11:59 | neat[未注册用户]

上面我的问题不知zhuweisky及各位知情者能否帮忙解答,可以回复,也可以直接通过msn联系:[email protected],在此先谢了!

回复 引用

#6楼2006-02-22 19:14 | zhuweisky1[未注册用户]

@neat:
WebService 的只要作用就是整合异构平台,所以使用.NET调用Java写的WebService肯定是没有问题的。
因改不是namespace的问题,由于动态代理在运行时创建,所以namespace几乎是不重要的。

回复 引用

#7楼2006-07-07 21:21 | 过河的卒子[未注册用户]

JWS不能被C#动态生成WS的调用类,是因为ServiceDescription不能正确解析Java的WSDL。至今没有解决!

回复 引用

#8楼2006-09-18 08:47 | weko[匿名][未注册用户]

谢谢分享

回复 引用

#9楼2007-06-06 01:06 | xud[未注册用户]

好是好,我用了下,可是不能对包含复杂数据类型的web服务进行调用。
请搂主和各位高手解释一下。

回复 引用

#10楼2008-06-04 09:58 | OXYGEN[未注册用户]

楼主你好,看了你的大作,个人觉得很好,希望以后多多发表一些类似的文章.最后希望楼主有源码没?发给我一份研究研究,谢谢!

回复 引用 查看

#11楼2009-02-24 13:54 | 张波sun

不错

回复 引用 查看

#12楼2009-03-24 17:19 | 张蒙蒙

我强烈顶你,你就是牛逼人,我找了好多天动态服务怎么调用了,大哥,我感谢你55太感动了,好人啊。

回复 引用 查看

#13楼2010-08-13 21:01 | zhao896

不错
mark

回复 引用 查看

#14楼2010-12-16 09:09 | wxf80106

请问楼主个问题:
如果所调用方法返回是int型的就会出错,string类型的可以。
出错在return mi.Invoke(obj,args);
说是不能转换,这个问题你考虑过吗?希望得到你的回复。

你可能感兴趣的:(Web)