通常我们在程序中需要调用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)
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
#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() ;
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#动态调用WebService
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Xml;
- using System.Net;
- using System.Web.Services.Description;
- using System.CodeDom;
- using System.CodeDom.Compiler;
- using System.Reflection;
- namespace WindowsServiceWebDefaultHotCity
- {
- /// <summary<
- /// WebService代理类
- /// </summary<
- public class WebServiceAgent
- {
- private object agent;
- private Type agentType;
- private const string CODE_NAMESPACE = "Beyondbit.WebServiceAgent.Dynamic";
- /// <summary<
- /// 构造函数
- /// </summary<
- /// <param name="url"<</param<
- public WebServiceAgent(string url)
- {
- XmlTextReader reader = new XmlTextReader(url + "?wsdl");
- //创建和格式化 WSDL 文档
- ServiceDescription sd = ServiceDescription.Read(reader);
- //创建客户端代理代理类
- ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
- sdi.AddServiceDescription(sd, null, null);
- //使用 CodeDom 编译客户端代理类
- CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);
- CodeCompileUnit ccu = new CodeCompileUnit();
- ccu.Namespaces.Add(cn);
- sdi.Import(cn, ccu);
- Microsoft.CSharp.CSharpCodeProvider icc = new Microsoft.CSharp.CSharpCodeProvider();
- CompilerParameters cp = new CompilerParameters();
- CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
- agentType = cr.CompiledAssembly.GetTypes()[0];
- agent = Activator.CreateInstance(agentType);
- }
- ///<summary<
- ///调用指定的方法
- ///</summary<
- ///<param name="methodName"<方法名,大小写敏感</param<
- ///<param name="args"<参数,按照参数顺序赋值</param<
- ///<returns<Web服务的返回值</returns<
- public object Invoke(string methodName, params object[] args)
- {
- MethodInfo mi = agentType.GetMethod(methodName);
- return this.Invoke(mi, args);
- }
- ///<summary<
- ///调用指定方法
- ///</summary<
- ///<param name="method"<方法信息</param<
- ///<param name="args"<参数,按照参数顺序赋值</param<
- ///<returns<Web服务的返回值</returns<
- public object Invoke(MethodInfo method, params object[] args)
- {
- return method.Invoke(agent, args);
- }
- public MethodInfo[] Methods
- {
- get
- {
- return agentType.GetMethods();
- }
- }
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Net;
using System.Web.Services.Description;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;
namespace WindowsServiceWebDefaultHotCity
{
/// <summary<
/// WebService代理类
/// </summary<
public class WebServiceAgent
{
private object agent;
private Type agentType;
private const string CODE_NAMESPACE = "Beyondbit.WebServiceAgent.Dynamic";
/// <summary<
/// 构造函数
/// </summary<
/// <param name="url"<</param<
public WebServiceAgent(string url)
{
XmlTextReader reader = new XmlTextReader(url + "?wsdl");
//创建和格式化 WSDL 文档
ServiceDescription sd = ServiceDescription.Read(reader);
//创建客户端代理代理类
ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
sdi.AddServiceDescription(sd, null, null);
//使用 CodeDom 编译客户端代理类
CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);
CodeCompileUnit ccu = new CodeCompileUnit();
ccu.Namespaces.Add(cn);
sdi.Import(cn, ccu);
Microsoft.CSharp.CSharpCodeProvider icc = new Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
agentType = cr.CompiledAssembly.GetTypes()[0];
agent = Activator.CreateInstance(agentType);
}
///<summary<
///调用指定的方法
///</summary<
///<param name="methodName"<方法名,大小写敏感</param<
///<param name="args"<参数,按照参数顺序赋值</param<
///<returns<Web服务的返回值</returns<
public object Invoke(string methodName, params object[] args)
{
MethodInfo mi = agentType.GetMethod(methodName);
return this.Invoke(mi, args);
}
///<summary<
///调用指定方法
///</summary<
///<param name="method"<方法信息</param<
///<param name="args"<参数,按照参数顺序赋值</param<
///<returns<Web服务的返回值</returns<
public object Invoke(MethodInfo method, params object[] args)
{
return method.Invoke(agent, args);
}
public MethodInfo[] Methods
{
get
{
return agentType.GetMethods();
}
}
}
}
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
- using System.Windows.Forms;
- namespace WindowsApplication1
- {
- public partial class Form1 : Form
- {
- private string _url = "http://www.baidu.com";
- public Form1()
- {
- InitializeComponent();
- init_Data();
- }
- public void init_Data()
- {
- WindowsServiceWebDefaultHotCity.WebServiceAgent agent = new WindowsServiceWebDefaultHotCity.WebServiceAgent(_url);
- object[] args = new object[6];
- args[0] = "PEK";
- args[1] = "CAN";
- args[2] = "";
- args[3] = "2008-08-02";
- args[4] = "00:00";
- args[5] = "own_9588";
- string text=agent.Invoke("GetAllFlight", args).ToString();
- textBox1.Text = text;
- }
- }
- }
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
private string _url = "http://www.baidu.com";
public Form1()
{
InitializeComponent();
init_Data();
}
public void init_Data()
{
WindowsServiceWebDefaultHotCity.WebServiceAgent agent = new WindowsServiceWebDefaultHotCity.WebServiceAgent(_url);
object[] args = new object[6];
args[0] = "PEK";
args[1] = "CAN";
args[2] = "";
args[3] = "2008-08-02";
args[4] = "00:00";
args[5] = "own_9588";
string text=agent.Invoke("GetAllFlight", args).ToString();
textBox1.Text = text;
}
}
}
该方法可以使程序不通过web引用的方式去调用webservices方法,直接在代码里调用该方法就能达到动态调用webservices的目的。使用前先引用System.Web.Services动态链接库,是.net自带的dll。
方法如下:
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Net;
- using System.IO;
- using System.Web.Services.Description;
- using System.CodeDom;
- using Microsoft.CSharp;
- using System.CodeDom.Compiler;
- namespace TestSkin
- {
- class Webservices
- {
- /// <summary<
- /// 实例化WebServices
- /// </summary<
- /// <param name="url"<WebServices地址</param<
- /// <param name="methodname"<调用的方法</param<
- /// <param name="args"<把webservices里需要的参数按顺序放到这个object[]里</param<
- public static object InvokeWebService(string url, string methodname, object[] args)
- {
- //这里的namespace是需引用的webservices的命名空间,在这里是写死的,大家可以加一个参数从外面传进来。
- string @namespace = "client";
- try
- {
- //获取WSDL
- WebClient wc = new WebClient();
- Stream stream = wc.OpenRead(url + "?WSDL");
- ServiceDescription sd = ServiceDescription.Read(stream);
- string classname = sd.Services[0].Name;
- 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
- {
- return null;
- }
- }
- }
- }