由于工作中需要,接触到了编译wsdl。
这次记录下 动态编译wsdl生成代理类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 WebserviceCallingTest
{
class WebserviceCalling
{
/// <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 = "MyWebserviceTest";
Console.WriteLine("定义命名空间:" + @namespace);
try
{
Console.WriteLine("开始获取wsdl...");
//获取WSDL
WebClient wc = new WebClient();
Console.WriteLine("开始获取流数据...");
Stream stream = wc.OpenRead(url + "?wsdl");
ServiceDescription sd = ServiceDescription.Read(stream);
Console.WriteLine("格式化流数据...");
string classname = sd.Services[0].Name;
Console.WriteLine("获取包含在流中的service集合中service[0].name:" + classname);
ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
Console.WriteLine("建立生成代理类功能类对象的实例...");
sdi.AddServiceDescription(sd, "", "");
/*
* sdi.ProtocolName = "SOAP";
* 这里说明下,协议类型有很多种,主要是 SOAP 和 SOAP12
* 如果这里不配置,可能会出现两种异常:
* 1. XML文档中< X,X >有错误
* 2. 命名空间 http://xxxxx/xxxx 无法导入到 xxxxxxxx 中。
*
* 另:如果配置了某一值,则只能使用这个值所代表的协议类型
* 建议:可以使用参数来传递协议类型。
*/
sdi.ProtocolName = "SOAP";
Console.WriteLine("配置访问XML的协议为:" + sdi.ProtocolName );
Console.WriteLine("将流数据加入实例中...");
CodeNamespace cn = new CodeNamespace(@namespace);
Console.WriteLine("生成命名空间对象...");
//生成客户端代理类代码
CodeCompileUnit ccu = new CodeCompileUnit();
Console.WriteLine("建立CodeDom容器对象...");
ccu.Namespaces.Add(cn);
Console.WriteLine("为容器添加命名空间...");
sdi.Import(cn, ccu);
Console.WriteLine("将命名空间和容器导入wsdl流中...");
CSharpCodeProvider csc = new CSharpCodeProvider();
Console.WriteLine("建立C#代码生成器和编译器对象...");
//ICodeCompiler icc = csc.CreateCompiler();
//设定编译参数
CompilerParameters cplist = new CompilerParameters();
Console.WriteLine("设置编译参数...");
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");
//这里的字段OutputAssembly可配置也可不配置,配置后下面的编译器对象将按照配置的路径将wsdl生成.dll文件
cplist.OutputAssembly = System.IO.Directory.GetCurrentDirectory() + "\\" + classname + ".dll";
Console.WriteLine("根据编译器对象按照编译参数对象和容器对象设置编译生成代理类对象...");
//编译代理类
CompilerResults cr = csc.CompileAssemblyFromDom(cplist, ccu);
Console.WriteLine("编译完成...");
Console.WriteLine("检测编译是否产生错误...");
if (File.Exists(System.IO.Directory.GetCurrentDirectory() + "\\" + classname + ".dll"))
{
Console.WriteLine(classname + ".dll" + "文件生成...");
}
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());
}
Console.WriteLine("开始调用编译完的程序集...");
//生成代理实例,并调用方法
/*
* 这里使用 System.Reflection.Assembly assembly = cr.CompiledAssembly 其实并不保险,assembly默认调用的是当前的程序集,
* 也就是默认调用的是WebserviceCalling(执行动态编译wsdl的程序集,就是本文),而不是编译成功的 Service.dll
* 所以,当执行assembly.GetType(@namespace + "." + classname, true, true)时,得到的 Type t 为null。
*/
Console.WriteLine("建立程序集对象...");
//System.Reflection.Assembly assembly = cr.CompiledAssembly;
/*
* 借用大神http://www.cnblogs.com/keyyang/p/3803920.html的解决办法
* 先加载 Service.dll
* Assembly asmb = Assembly.LoadFrom(classname + ".dll") ;
* 再获取程序集中的类型对象
* Type supType = asmb.GetType(@namespace + "." + classname) ;
*/
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(classname + ".dll");
Type t = assembly.GetType(@namespace + "." + classname, true, true);
Console.WriteLine("获取程序集中" + @namespace + "." + classname + "中的类型对象...");
object obj = Activator.CreateInstance(t);
Console.WriteLine("建立该对象实例...");
System.Reflection.MethodInfo mi = t.GetMethod(methodname);
Console.WriteLine("获取名为" + methodname + "的方法的信息....\n" + mi.ToString());
Console.WriteLine("开始调用该方法...");
return mi.Invoke(obj, args);
}
catch
{
return null;
}
}
static void Main(string[] args)
{
String url = "http://192.168.5.140:8090/Service1.asmx" ;
String methodname = "Add" ;
String param = "1,2" ;
Console.WriteLine("调用方法:" + methodname + ",传递参数:" + param.ToString());
Console.WriteLine("得到结果:" + InvokeWebService(url, methodname, param.Split(',')).ToString());
Console.ReadLine();
}
}
}
小弟我是刚刚开始学习编程,文章中所说为自己理解,如有不对的地方,请各位大神指正。