动态代理实现C#动态调用WebService

第三方公司一般使用Java、C#或者其他语言以wsdl的方式发布Web服务供我们使用,但在C#调用端不允许使用VS添加服务引用的方式进行调用(因为服务的url地址有可能经常变动,需要存储在数据库中进行维护),这种动态调用的方式就派上用场了。

需要添加System.Web.Services.dll的引用

代码如下:

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web.Services.Description;
using System.Xml.Serialization;

namespace WpfDemo1
{
    class WcfHelper
    {
        /// <summary>
        /// WebService服务代理
        /// </summary>
        public class WebServiceProxy
        {
            /// <summary>
            /// 命名空间
            /// </summary>
            private string ClassName = null;

            /// <summary>
            /// WebServiceURL地址
            /// </summary>
            private string WebServiceUrl { get; set; }

            /// <summary>
            /// WebService服务代理构造方法
            /// </summary>
            /// <param name="webServiceUrl">WebServiceURL地址</param>
            private WebServiceProxy(string webServiceUrl)
            {
                this.WebServiceUrl = webServiceUrl + "?WSDL";
                this.ClassName = webServiceUrl.Substring(webServiceUrl.LastIndexOf('/') + 1);
                this.ClassName = ClassName.Substring(0, ClassName.LastIndexOf('.'));
            }

            /// <summary>
            /// 根据编译结果生成实例并返回
            /// </summary>
            /// <param name="webServiceUrl">WebServiceURL地址</param>
            /// <returns>根据编译结果生成实例并返回</returns>
            public static object CreateInstance(string webServiceUrl)
            {
                WebServiceProxy proxy = new WebServiceProxy(webServiceUrl);
                CodeCompileUnit unit = proxy.GetServiceCompileUnit(proxy.WebServiceUrl);
                CompilerResults result = proxy.Compile(unit);
                Assembly asm = result.CompiledAssembly;
                return asm.CreateInstance("WebService." + proxy.ClassName);
            }

            /// <summary>
            /// 获得CodeDOM 程序图形容器
            /// </summary>
            /// <param name="webServiceUrl">WebServiceURL地址</param>
            /// <returns>获得CodeDOM 程序图形容器</returns>
            private CodeCompileUnit GetServiceCompileUnit(string webServiceUrl)
            {
                WebClient client = new WebClient();
                Stream stream = client.OpenRead(webServiceUrl);
                //从这个url指向的的是一个xml文件,里面包含了该service的全部信息。
                //进而通过解析xml文件从而可以生成要编译的源码。有兴趣的可以看一下xml的内容
                ServiceDescription description = ServiceDescription.Read(stream);
                ServiceDescriptionImporter importer = new ServiceDescriptionImporter();//创建客户端代理
                importer.ProtocolName = "Soap"; //指定访问协议。
                importer.Style = ServiceDescriptionImportStyle.Client; //生成客户端代理。
                importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
                importer.AddServiceDescription(description, "", ""); //添加WSDL文档。
                CodeNamespace nmspace = new CodeNamespace(); //命名空间
                nmspace.Name = "WebService";
                CodeCompileUnit unit = new CodeCompileUnit();
                unit.Namespaces.Add(nmspace);
                ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
                return unit;
            }

            /// <summary>
            /// 编译
            /// </summary>
            /// <param name="unit">CodeDOM 程序图形容器</param>
            /// <returns>返回从编译器返回的编译结果</returns>
            private CompilerResults Compile(CodeCompileUnit unit)
            {
                CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("CSharp");
                CompilerParameters compilerParameters = new CompilerParameters();
                compilerParameters.GenerateExecutable = false;
                compilerParameters.GenerateInMemory = true;
                // cp.OutputAssembly = "D:\\Test.dll";这里也可以将变异的结果输出到dll文件中,从而可以查看编译的的结果。有兴趣的自己看一下。
                compilerParameters.ReferencedAssemblies.Add("System.dll");
                compilerParameters.ReferencedAssemblies.Add("System.XML.dll");
                compilerParameters.ReferencedAssemblies.Add("System.Web.Services.dll");
                compilerParameters.ReferencedAssemblies.Add("System.Data.dll");
                CompilerResults compilerResults = codeDomProvider.CompileAssemblyFromDom(compilerParameters, unit);
                if (compilerResults.Errors.HasErrors)
                {
                    string errors = "";
                    foreach (var item in compilerResults.Errors)
                    {
                        errors += item.ToString() + Environment.NewLine;
                    }

                    throw new Exception("Compile error:" + errors);
                }
                return compilerResults;
            }

            /// <summary>
            /// Web服务调用
            /// </summary>
            /// <param name="webServiceUrl">服务URL</param>
            /// <param name="methodName">服务方法名称</param>
            /// <param name="parameters">方法参数</param>
            /// <returns></returns>
            public static object Invoke(string webServiceUrl, string methodName, object[] parameters)
            {
                if (string.IsNullOrEmpty(webServiceUrl))
                    throw new Exception("WebService的URL地址为空!");
                if (string.IsNullOrEmpty(methodName))
                    throw new Exception("WebService的方法名为空!");

                object instance = WebServiceProxy.CreateInstance(webServiceUrl);
                MethodInfo method = instance.GetType().GetMethod(methodName);
                return method.Invoke(instance, parameters);
            }
        }
    }
}

调用:WebServiceProxy.Invoke("WebService的URL地址","WebService的方法名","方法的参数");

 

最重要的是编译wsdl,然后使用反射技术进行动态调用

注意:WebService的URL地址不带?wsdl,如果没有方法的参数,还得自己使用反射的技术进行处理

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值