c#中动态编译wsdl并调用接口

由于工作中需要,接触到了编译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();
        }
    }
}


小弟我是刚刚开始学习编程,文章中所说为自己理解,如有不对的地方,请各位大神指正。


测试结果如图:




以下是C#调用wsdl接口的三种方法示例: 1. 使用Visual Studio自动生成代理类: ```csharp // 引用WebService接口 using WebServiceNamespace; // 创建代理类实例 WebServiceClient client = new WebServiceClient(); // 调用接口方法 string result = client.MethodName(parameter); ``` 2. 使用命令行工具wsdl.exe生成代理类: ```shell // 打开命令提示符 // 进入wsdl.exe所在目录 // 执行以下命令生成代理wsdl /language:c# /out:生成类的物理路径 /url:WebService接口URL或wsdl文件路径 // 在代码引用生成代理类 using WebServiceNamespace; // 创建代理类实例 WebServiceClient client = new WebServiceClient(); // 调用接口方法 string result = client.MethodName(parameter); ``` 3. 手动解析wsdl文件: ```csharp // 引用System.Web.Services和System.Web.Services.Description命名空间 using System.Web.Services; using System.Web.Services.Description; using System.Xml; // 创建WebService描述文件的URL string wsdlUrl = "WebService接口URL或wsdl文件路径"; // 创建ServiceDescription对象 ServiceDescription serviceDescription = ServiceDescription.Read(wsdlUrl); // 创建ServiceDescriptionImporter对象 ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); importer.ProtocolName = "Soap"; // 指定协议为Soap // 添加ServiceDescription对象 importer.AddServiceDescription(serviceDescription, null, null); // 创建CodeNamespace对象 CodeNamespace codeNamespace = new CodeNamespace("WebServiceNamespace"); // 创建CodeCompileUnit对象 CodeCompileUnit codeCompileUnit = new CodeCompileUnit(); codeCompileUnit.Namespaces.Add(codeNamespace); // 生成代理类代码 ServiceDescriptionImportWarnings warnings = importer.Import(codeNamespace, codeCompileUnit); // 使用CodeDomProvider编译代理类 CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("CSharp"); CompilerParameters compilerParameters = new CompilerParameters(); compilerParameters.GenerateExecutable = false; compilerParameters.GenerateInMemory = true; CompilerResults compilerResults = codeDomProvider.CompileAssemblyFromDom(compilerParameters, codeCompileUnit); // 获取生成代理类类型 Type proxyType = compilerResults.CompiledAssembly.GetTypes().FirstOrDefault(t => t.Name == "WebServiceClient"); // 创建代理类实例 object proxyInstance = Activator.CreateInstance(proxyType); // 调用接口方法 MethodInfo method = proxyType.GetMethod("MethodName"); string result = (string)method.Invoke(proxyInstance, new object[] { parameter }); ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值