通常我们在程序中需要调用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;
}
}
}
- 我们都知道,调用WS可以在工程中添加对WS的WEB引用。
- 但是,如果我们不想通过添加引用的方式,而是在代码中动态引用该怎么办呢?
- 首先,我们该想到WS的实现也是一个类的形式。
- 其次,WS在传输过程中是通过WSDL来进行描述的(使用SOAP协议)。
- 因此,我们需要获取WS的WSDL描述,并通过该描述来动态生成程序集。
- 最后:通过反射来获取新生成的程序集,并调用其方法!
- 上述步骤需要引用如下四个名称空间:
- using System.Web.Services.Description; //WS的描述
- //以下几个用于根据描述动态生成代码并动态编译获取程序集
- using System.CodeDom;
- using Microsoft.CSharp;
- using System.CodeDom.Compiler;
- 上述几个名称空间中包括如下几个重要的类:
- using System.Web.Services.Description下:
- ServiceDescription //WS描述
- ServiceDescriptionImporter //通过描述生成客户端代理类,特别注意其中的Style
- 以下是MSDN对其的描述:
- XML Web services 的接口通常由 Web 服务描述语言 (WSDL) 文件来说明。例如,若要获取有关使用 http://localhost/service.asmx 处公开的 ASP.NET 的 Web 服务的 WSDL 说明,只需导航到 http://localhost/service.asmx?WSDL。使用 ServiceDescriptionImporter 类可以方便地将 WSDL 说明中包含的信息导入到 System.CodeDom.CodeCompileUnit 对象。通过调整 Style 参数的值,可以指示 ServiceDescriptionImporter 实例生成客户端代理类(通过透明调用该类可提供 Web 服务的功能)或生成抽象类(该类封装 Web 服务的功能而不实现该功能)。如果将 Style 属性设置为 Client,则 ServiceDescriptionImporter 生成客户端代理类,通过调用这些类来提供说明的 Web 服务的功能。如果将 Style 属性设置为 Server,则 ServiceDescriptionImporter 实例生成抽象类,这些类表示所说明的 XML Web services 的功能而不进行实现。然后,可以通过编写从这些抽象类继承的类来对其进行实现,并实现相关的方法。
- using System.CodeDom下:
- CodedomUnit //它用于设定动态代码的名称空间,类名等,可以通过ServiceDescriptionImporter.Import()方法将WS的描述代码写入该类,以作动态编译用
我们都知道,调用WS可以在工程中添加对WS的WEB引用。
但是,如果我们不想通过添加引用的方式,而是在代码中动态引用该怎么办呢?
首先,我们该想到WS的实现也是一个类的形式。
其次,WS在传输过程中是通过WSDL来进行描述的(使用SOAP协议)。
因此,我们需要获取WS的WSDL描述,并通过该描述来动态生成程序集。
最后:通过反射来获取新生成的程序集,并调用其方法!
上述步骤需要引用如下四个名称空间:
using System.Web.Services.Description; //WS的描述
//以下几个用于根据描述动态生成代码并动态编译获取程序集
using System.CodeDom;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
上述几个名称空间中包括如下几个重要的类:
using System.Web.Services.Description下:
ServiceDescription //WS描述
ServiceDescriptionImporter //通过描述生成客户端代理类,特别注意其中的Style
以下是MSDN对其的描述:
XML Web services 的接口通常由 Web 服务描述语言 (WSDL) 文件来说明。例如,若要获取有关使用 http://localhost/service.asmx 处公开的 ASP.NET 的 Web 服务的 WSDL 说明,只需导航到 http://localhost/service.asmx?WSDL。使用 ServiceDescriptionImporter 类可以方便地将 WSDL 说明中包含的信息导入到 System.CodeDom.CodeCompileUnit 对象。通过调整 Style 参数的值,可以指示 ServiceDescriptionImporter 实例生成客户端代理类(通过透明调用该类可提供 Web 服务的功能)或生成抽象类(该类封装 Web 服务的功能而不实现该功能)。如果将 Style 属性设置为 Client,则 ServiceDescriptionImporter 生成客户端代理类,通过调用这些类来提供说明的 Web 服务的功能。如果将 Style 属性设置为 Server,则 ServiceDescriptionImporter 实例生成抽象类,这些类表示所说明的 XML Web services 的功能而不进行实现。然后,可以通过编写从这些抽象类继承的类来对其进行实现,并实现相关的方法。
using System.CodeDom下:
CodedomUnit //它用于设定动态代码的名称空间,类名等,可以通过ServiceDescriptionImporter.Import()方法将WS的描述代码写入该类,以作动态编译用
using System.CodeDom.Compiler下:
CodedomProvider
//用于创建和检索代码生成器和代码编译器的实例,我们主要用到其实现子类CShareCodeProvider
可以直接用CShareCodeProvider
provider=new
CShareCodeProvider()来生成,或者用CodedomProvider.CreateProvider("CSharp")来生成
ICodeCompiler
//用于编译基于 System.CodeDom
的源代码表示形式。
它通过CodedomProvider的CreateCompiler()方法来
CompilerResults
//表示从编译器返回的编译结果。 它由ICodeCompiler根据指定的编译器设置从指定的 CodeCompileUnit 所包含的
System.CodeDom 树中编译程序集并返回。CompiledAssembly 属性指示编译的程序集。
了解如上信息后,就可动态调用WS了。
如下是摘自http://www.cnblogs.com/ruochen/archive/2007/12/11/990427.html的代码演示:
Code
该方法可以使程序不通过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;
- }
- }
- }
- }
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;
}
}
}
}
===了解上述类和方法后,基本就可以动态调用WS了。
特别注意的是:动态编译后需要用到反射来读取并执行。因此需要您了解什么是反射及如何反射。
web
service的动态调用,主要有三种方法。
1、修改config文件。只要你引用了web
service,就会在config文件中出现asmx文件的地址。只需要修改该地址即可。
2、程序修改url。web
service是集成了System.Web.Service.WebService类的,而该类有一个Url属性。通过修改该属性可以达到与方法一一样的效果,并且比它还要灵活。有的时候,我们需要提供一个列表,有很多的服务器让用户选择。程序根据用户的选择连接到不同的服务器上调用web
service。这时,就可以用这个方法了。
3、接口引用。有的时候,我们需要调用不同服务器上的web
service,但他们彼此又不一样,只是都实现了同一个接口。这时候,就可以考虑下面的这个方法。只要先引用所有的web
service,然后用接口实例来保存创建出来的web
service对象即可。
4、动态编译。这个应该算得上是真正意义上的动态了。有的时候,各个服务器上的web
service更新比较快,我们不可能天天去更新代理类的,这个时候就可以用这个方法了。
在该方法中,有一点限制。就是各个服务器的web
service,要么是都继承了同一个接口,要么是都有一些同样签名的方法,而且service的类名最好是一样的。不过就算不符合这条件也没关系,后面我会在注释中注明的。看代码:
- using System;
- using System.CodeDom;
- using System.CodeDom.Compiler;
- using System.IO;
- using System.Net;
- using System.Reflection;
- using System.Web.Services.Description;
- using Microsoft.CSharp;
- //获取Web Service描述
- WebClient wc= new WebClient();
- Stream stream = wc.OpenRead("http://localhost/TestService.asmx?WSDL"); //这里指定你自己的web service url,一定要以?WSDL结尾
- ServiceDescription sd = ServiceDescription.Read(stream);
- ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
- sdi.ProtocolName = "soap";
- sdi.Style = ServiceDescriptionImportStyle.Client;
- sdi.AddServiceDescription(sd, null, null);
- //指定命名空间
- CodeNamespace cn = new CodeNamespace("Test"); //这里随便指定一个命名空间,但要与后面的一致
- CodeCompileUnit ccu = new CodeCompileUnit();
- ccu.Namespaces.Add(cn);
- sdi.Import(cn, ccu);
- 建立C#编译器
- CSharpCodeProvider csc = new CSharpCodeProvider();
- ICodeCompiler icc = csc.CreateCompiler();
- CompilerParameters cp = new CompilerParameters();
- cp.GenerateExecutable = false;
- cp.GenerateInMemory = true;
- //添加编译条件
- cp.ReferencedAssemblies.Add("System.dll");
- cp.ReferencedAssemblies.Add("System.XML.dll");
- cp.ReferencedAssemblies.Add("System.Web.Services.dll");
- //编译程序集
- CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
- //检查是否编译成功
- if (!cr.Errors.HasErrors)
- {
- //编译成功
- //获取程序集
- Assembly assembly = cr.CompiledAssembly;
- //获取程序集类型
- //前面的Test就是命名空间,必须要与前面指定的一致
- //后面的TestService就是service的类名
- //如果所有的服务器都是一致的类名,这里就可以写死,否则要动态提供类名
- Type type = assembly.GetType("Test.TestService", true);
- object service = Activator.CreateInstance(type);
- //获取方法
- //如果所有的服务器都是一致的方法名,这里可以写死,否则就要动态提供方法名
- MethodInfo mi = type.GetMethod("HelloWorld");
- //调用方法
- //如果方法没有参数,第二个参数可以传递null,否则就要传递object数组,数组元素的顺序要与参数的顺序一致
- //如果所有服务器的方法签名都是一致的,object数组的顺序就可以写死了,否则还要动态调整元素的数量及顺序
- mi.Invoke(service, null);
- //最后,返回的是object类型,根据方法的签名,把返回值转换成不同的对象即可。
- }
- else
- {
- //这里自己处理编译错误
- }
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Net;
using System.Reflection;
using System.Web.Services.Description;
using Microsoft.CSharp; //获取Web Service描述
WebClient wc= new WebClient();
Stream stream = wc.OpenRead("http://localhost/TestService.asmx?WSDL"); //这里指定你自己的web service url,一定要以?WSDL结尾
ServiceDescription sd = ServiceDescription.Read(stream);
ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
sdi.ProtocolName = "soap";
sdi.Style = ServiceDescriptionImportStyle.Client;
sdi.AddServiceDescription(sd, null, null);
//指定命名空间
CodeNamespace cn = new CodeNamespace("Test"); //这里随便指定一个命名空间,但要与后面的一致
CodeCompileUnit ccu = new CodeCompileUnit();
ccu.Namespaces.Add(cn);
sdi.Import(cn, ccu);
建立C#编译器
CSharpCodeProvider csc = new CSharpCodeProvider();
ICodeCompiler icc = csc.CreateCompiler();
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
//添加编译条件
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.XML.dll");
cp.ReferencedAssemblies.Add("System.Web.Services.dll");
//编译程序集
CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);
//检查是否编译成功
if (!cr.Errors.HasErrors)
{
//编译成功
//获取程序集
Assembly assembly = cr.CompiledAssembly;
//获取程序集类型
//前面的Test就是命名空间,必须要与前面指定的一致
//后面的TestService就是service的类名
//如果所有的服务器都是一致的类名,这里就可以写死,否则要动态提供类名
Type type = assembly.GetType("Test.TestService", true);
object service = Activator.CreateInstance(type);
//获取方法
//如果所有的服务器都是一致的方法名,这里可以写死,否则就要动态提供方法名
MethodInfo mi = type.GetMethod("HelloWorld");
//调用方法
//如果方法没有参数,第二个参数可以传递null,否则就要传递object数组,数组元素的顺序要与参数的顺序一致
//如果所有服务器的方法签名都是一致的,object数组的顺序就可以写死了,否则还要动态调整元素的数量及顺序
mi.Invoke(service, null);
//最后,返回的是object类型,根据方法的签名,把返回值转换成不同的对象即可。
}
else
{
//这里自己处理编译错误
}
动态调用WebService(C#) (非常实用)的更多相关文章
-
Asp.net动态调用WebService
Public Class WebServiceHelper #Region "InvokeWebService" '动态调用web服务 Public Shared Function ...
-
Atitit 动态调用webservice与客户端代理方式调用
Atitit 动态调用webservice与客户端代理方式调用 方式1: 使用call.invoke 直接调用WSDL,缺点:麻烦,不推荐--特别是JAVA调用.NET的WS时,会有不少的问题需要解 ...
-
动态调用webservice(部分转载)
动态调用webservice,做个笔记: public class WSHelper { /// < summary> /// 动态调用web服务 /// < /summary> ...
-
C# 动态调用webservice
最近项目中,用到动态调用webservice的内容,此处记录下来,留着以后COPY(我们只需要在XML,config文件,或者数据库中配置webservice连接地址和方法名即可使用): using ...
-
动态调用webservice及WCF服务
动态调用web服务,该方法只针对Web service, WCF的服务不行,如果是WCF的就通过工具直接生产代理类,把代理类配置到调用的项目中,通过配置客户端的终结点动态的取实现: 通过Svcutil ...
-
C# .NET 动态调用webservice的三种方式
转载自 百度文库 http://wenku.baidu.com/link?url=Q2q50wohf5W6UX44zqotXFEe_XOMaib4UtI3BigaNwipOHKNETloMF4ax4W ...
-
WebService – 2.动态调用WebService
在本节课程中,将演示如何通过程序动态添加.调用.编译.执行WebService并返回结果. WebService动态调用示意图 WebService相关知识 代码文档对象模型CodeDom的使用 编程 ...
-
用C#通过反射实现动态调用WebService 告别Web引用
我们都知道,调用WebService可以在工程中对WebService地址进行WEB引用,但是这确实很不方便.我想能够利用配置文件灵活调用WebService.如何实现呢? 用C#通过反射实现动态调用 ...
-
动态调用Webservice 支持Soapheader身份验证(转)
封装的WebserviceHelp类: using System; using System.CodeDom; using System.CodeDom.Compiler; using System. ...
随机推荐
-
REGEX例子
作为REGEX的例子,代码9.3显示了一个给定的文件有多少行,具有给定的模式,通过命令行输入(注:有更有效率的方式来实现这个功能,如Unix下的grep命令,在这里只是给出了另一种方式).这个程序像下 ...
-
16位汇编 多文件 intel汇编 编译器masm5.0 调用子程序库即静态库的自定义函数 WINDOWS
;以下是16位汇编 创建静态库,并调用静态库中的函数 ;多文件汇编格式 ;编译方法(此处用的是masm 5.0,如果是其他的编译器,有可能不能编译) ;第一种,编译方法 ;1.masm main.as ...
-
使用Github Pages创建自己的网站
这是一篇使用Github Pages创建自己网站的教程,操作很简单,相信,亲们肯定一学就会,但是大家也要有一定的github基础呀,所以小编给大家附上一个链接(http://www.cnblogs.c ...
-
CentOS6.4 安装 mongo-connector
mongo-connector在python2.6.6版本下安装不成功,官方测试2.7,3.3正常 需要升级python2.7 具体步骤: 安装开发工具包: yum groupinstall &quo ...
-
ueditor爬坑
在使用UeEditor中遇到几个个坑 1.添加的html代码中使用的样式class被guolv掉 解决方案:在ueditor.config.js中,xss过滤白名单中,每个元素添加class,如下图 ...
-
局域网git服务器搭建(基于win7 + bonobo git server)
公司内网有一台win7系统的服务器. 准备在上面部署git后台, 用于内网项目版本管理. 搜索了相关资料后, 在根据公司环境, 决定采用win7 + bonobo git server + git的方 ...
-
使用AtomicLong,经典银行账户问题
1.新建Account类,使用AtomicLong定义账户余额,增加和减少金额方法使用getAndAdd方法. package com.xkzhangsan.atomicpack.bank; impo ...
-
单链表的python实现
首先说下线性表,线性表是一种最基本,最简单的数据结构,通俗点讲就是一维的存储数据的结构. 线性表分为顺序表和链接表: 顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素,称为线性表的顺序存 ...
-
[hgoi#2019/2/16t2]friend
题目描述 在一个遥远的国度里有n个人,每个人手上写着4个互不相同的数. 这个国度比较奇怪,如果两个人至少有一个数字相同,则他们是一对朋友. 现在这n个人按序号从左到右排成了一排,每个人都想知道在他左边 ...
-
EEPROM读写学习笔记与I2C总线(转)
reference:https://www.cnblogs.com/uiojhi/p/7565232.html 无论任何电子产品都会涉及到数据的产生与数据的保存,这个数据可能并不是用来长久保存,只是在 ...