• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    .NET的动态编译与WS服务调用详解

        动态编译与WS服务,有关系么?今天就乱弹一番,如何使用动态编译动态生成WS服务调用的代理类,然后通过这个代理类调用WS服务。
        首先,动态编译这玩意在.NET里面是非常简单的,实际上只涉及到两个类型:CodeDomProvider以及CompilerParameters他们都位于System.CodeDom.Compiler命名空间。
        以下代码可将源码动态编译为一个程序集:
    动态编译

    复制代码 代码如下:

    CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
    CompilerParameters codeParameters = new CompilerParameters();
    codeParameters.GenerateExecutable = false; //编译为dll,如果为true则编译为exe
    codeParameters.GenerateInMemory = true; //编译后的程序集保存到内存中
    StringBuilder code = new StringBuilder();
    //此处构造源代码
    CompilerResults results = provider.CompileAssemblyFromSource(codeParameters, code.ToString());
    Assembly assembly = null; //动态编译生成的程序集
    if (!results.Errors.HasErrors)
    {
        assembly = results.CompiledAssembly;
    }

        获得assembly后,随后我们即可以通过反射获取程序集里面的类型,然后实例化,调用类型方法…
        不过在此之前,我们得构造WS服务的代理类,它是什么样子的呢?我们使用WCF框架,创建服务代理类也是十分简单的,常见的代理类结构如下:
    服务调用代理类
    复制代码 代码如下:

    [ServiceContract(Namespace="https://www.jb51.net/")]
    public interface TestService
    {
        [OperationContract(Action = "https://www.jb51.net/HelloWorld", ReplyAction = "https://www.jb51.net/HelloWorldResponse")]
        string HelloWorld();
    }
    public class TestServiceClient : ClientBaseTestService>, TestService
    {
        public TestServiceClient(Binding binding, EndpointAddress address) :
            base(binding, address)
        {
        }
        public string HelloWorld()
        {
            return base.Channel.HelloWorld();
        }
    }

        所以,我们要动态构造出代理类源码,应该知道服务的命名空间、服务方法的Action地址、ReplyAction地址,当然还有服务方法的名称,返回类型,参数列表。这里,我们省略掉服务方法的参数列表,构造代理类,实际上就是一个字符串组装的问题,先创建一个类型,用于保存构造代理类所要用到的参数:

    服务代理类构造参数

    复制代码 代码如下:

    public class WebServiceParamaters
    {
        public string address;
        public string Address
        {
            get { return address; }
            set
            {
                address = value;
            }
        }
        private string serviceNamespace;
        public string ServiceNamespace
        {
            get { return serviceNamespace; }
            set
            {
                serviceNamespace = value;
            }
        }
       private string methodAction;
        public string MethodAction
        {
            get { return methodAction; }
            set
            {
                methodAction = value;
            }
        }
        private string methodReplyAction;
        public string MethodReplyAction
        {
            get { return methodReplyAction; }
            set
            {
                methodReplyAction = value;
            }
        }
        private string methodName;
        public string MethodName
        {
            get { return methodName; }
            set
            {
                methodName = value;
            }
        }
        private string returnType;
        public string ReturnType
        {
            get { return returnType; }
            set
            {
                returnType = value;
            }
        }
    }

     好,现在我们只需要构造出代理类源码,然后动态编译出代理类的程序集,最后通过反射调用服务方法:
    WebServiceProxyCreator
    复制代码 代码如下:

    public class WebServiceProxyCreator
    {
        public Object WebServiceCaller(WebServiceParamaters parameters)
        {
            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
            CompilerParameters codeParameters = new CompilerParameters();
            codeParameters.GenerateExecutable = false;
            codeParameters.GenerateInMemory = true;
            StringBuilder code = new StringBuilder();
            CreateProxyCode(code, parameters);
    codeParameters.ReferencedAssemblies.Add("System.dll");
    codeParameters.ReferencedAssemblies.Add("System.ServiceModel.dll");
            CompilerResults results = provider.CompileAssemblyFromSource(codeParameters, code.ToString());
            Assembly assembly = null;
            if (!results.Errors.HasErrors)
            {
                assembly = results.CompiledAssembly;
            }
            Type clientType = assembly.GetType("RuntimeServiceClient");
           ConstructorInfo ci = clientType.GetConstructor(new Type[] { typeof(Binding), typeof(EndpointAddress) });
            BasicHttpBinding binding = new BasicHttpBinding(); //只演示传统的WebService调用
            EndpointAddress address = new EndpointAddress(parameters.address);
            Object client = ci.Invoke(new object[] { binding, address });
            MethodInfo mi = clientType.GetMethod(parameters.MethodName);
            Object result = mi.Invoke(client, null);
            mi = clientType.GetMethod("Close"); //关闭代理
            mi.Invoke(client, null);
            return result;
       }
        public static void CreateProxyCode(StringBuilder code, WebServiceParamaters parameters)
        {
            code.AppendLine("using System;");
            code.AppendLine("using System.ServiceModel;");
            code.AppendLine("using System.ServiceModel.Channels;");
            code.Append(@"[ServiceContract(");
            if (!String.IsNullOrEmpty(parameters.ServiceNamespace))
            {
                code.Append("Namespace=\"").Append(parameters.ServiceNamespace).Append("\"");
            }
            code.AppendLine(")]");
            code.AppendLine("public interface IRuntimeService");
            code.AppendLine("{");
            code.Append("[OperationContract(");
            if (!String.IsNullOrEmpty(parameters.MethodAction))
            {
                code.Append("Action=\"").Append(parameters.MethodAction).Append("\"");
                if (!String.IsNullOrEmpty(parameters.MethodReplyAction))
                {
                    code.Append(", ");
                }
            }
            if (!String.IsNullOrEmpty(parameters.MethodReplyAction))
            {
                code.Append("ReplyAction=\"").Append(parameters.MethodReplyAction).Append("\"");
            }
            code.AppendLine(")]");
            code.Append(parameters.ReturnType).Append(" ");
            code.Append(parameters.MethodName).AppendLine("();");
            code.AppendLine("}");
            code.AppendLine();
            code.AppendLine("public class RuntimeServiceClient : ClientBaseIRuntimeService>, IRuntimeService");
            code.AppendLine("{");
            code.AppendLine("public RuntimeServiceClient(Binding binding, EndpointAddress address) :base(binding, address)");
            code.AppendLine("{");
            code.AppendLine("}");
            code.Append("public ").Append(parameters.ReturnType).Append(" ");
            code.Append(parameters.MethodName).AppendLine("()");
            code.AppendLine("{");
            code.Append("return base.Channel.").Append(parameters.MethodName).AppendLine("();");
            code.AppendLine("}");
            code.AppendLine("}");
        }
    }

      注意,红色部分,由于代理类使用了WCF框架,所以编译时我们需要添加System.ServiceModel的引用,当然System.dll肯定是必须的,这里要注意,System.ServiceModel.dll应该保存到应用程序目录,否则动态编译时会引发异常,很简单,在工程引用中添加System.ServiceModel的引用,然后在属性中将拷贝到本地属性设置为true。
       到此,我们就可以直接通过传入的服务地址、服务方法名称以及相关的命名空间,即可调用服务(尽管我们只能调用无参服务,并且尽管我们也只能调用使用BasicHttpBinding绑定的服务,这些限制的原因是…我懒,好吧,相信只要经过一点改动即可去掉这些限制)。
       可惜,我们的程序还很傻:每次调用服务都需要去生成代码、编译、创建代理实例最后再调用,嗯…那就缓存吧:
      在WebServiceParameters类中重写GetHashCode方法:
    复制代码 代码如下:

     public override int GetHashCode()
      {
          return String.Concat(serviceNamespace, methodAction, methodReplyAction, methodName, returnType).GetHashCode();
      }


    然后在WebServiceProxyCreator中加入缓存机制:
    复制代码 代码如下:

      public class WebServiceProxyCreator
       {
           private static Dictionaryint, Type> proxyTypeCatch = new Dictionaryint, Type>();

           public Object WebServiceCaller(WebServiceParamaters parameters)
           {
               int key = parameters.GetHashCode();
               Type clientType = null;
               if (proxyTypeCatch.ContainsKey(key))
              {
                  clientType = proxyTypeCatch[key];
                  Debug.WriteLine("使用缓存");
              }
              else
              {

                  CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
                  CompilerParameters codeParameters = new CompilerParameters();
                  codeParameters.GenerateExecutable = false;
                  codeParameters.GenerateInMemory = true;

                  StringBuilder code = new StringBuilder();
                  CreateProxyCode(code, parameters);

                  codeParameters.ReferencedAssemblies.Add("System.dll");
                  codeParameters.ReferencedAssemblies.Add("System.ServiceModel.dll");

                  CompilerResults results = provider.CompileAssemblyFromSource(codeParameters, code.ToString());
                  Assembly assembly = null;
                  if (!results.Errors.HasErrors)
                  {
                      assembly = results.CompiledAssembly;
                  }

                  clientType = assembly.GetType("RuntimeServiceClient");

                  proxyTypeCatch.Add(key, clientType);
              }
              ConstructorInfo ci = clientType.GetConstructor(new Type[] { typeof(Binding), typeof(EndpointAddress) });
              BasicHttpBinding binding = new BasicHttpBinding(); //只演示传统的WebService调用
              EndpointAddress address = new EndpointAddress(parameters.address);
              Object client = ci.Invoke(new object[] { binding, address });

              MethodInfo mi = clientType.GetMethod(parameters.MethodName);
              Object result = mi.Invoke(client, null);
              mi = clientType.GetMethod("Close"); //关闭代理
              mi.Invoke(client, null);
              return result;
          }

     }

    您可能感兴趣的文章:
    • 详细介绍.NET中的动态编译技术
    • 使用 C# 动态编译代码和执行的代码
    • C# 动态编译、动态执行、动态调试
    • .NET 动态编译
    • c#动态编译执行对象方法示例 运用映射机制创建对象
    上一篇:Asp.Net用OWC操作Excel的实例代码
    下一篇:ASP.NET打开新页面而不关闭原来的页面 实例代码
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    .NET的动态编译与WS服务调用详解 .NET,的,动态,编译,与,服务,