源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

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

  • 时间:2022-07-27 23:35 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:.NET的动态编译与WS服务调用详解
    动态编译与WS服务,有关系么?今天就乱弹一番,如何使用动态编译动态生成WS服务调用的代理类,然后通过这个代理类调用WS服务。     首先,动态编译这玩意在.NET里面是非常简单的,实际上只涉及到两个类型:CodeDomProvider以及CompilerParameters他们都位于System.CodeDom.Compiler命名空间。     以下代码可将源码动态编译为一个程序集: 动态编译
[u]复制代码[/u] 代码如下:
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框架,创建服务代理类也是十分简单的,常见的代理类结构如下: 服务调用代理类
[u]复制代码[/u] 代码如下:
[ServiceContract(Namespace="http://www.1sucai.cn/")] public interface TestService {     [OperationContract(Action = "http://www.1sucai.cn/HelloWorld", ReplyAction = "http://www.1sucai.cn/HelloWorldResponse")]     string HelloWorld(); } public class TestServiceClient : ClientBase<TestService>, TestService {     public TestServiceClient(Binding binding, EndpointAddress address) :         base(binding, address)     {     }     public string HelloWorld()     {         return base.Channel.HelloWorld();     } }
    所以,我们要动态构造出代理类源码,应该知道服务的命名空间、服务方法的Action地址、ReplyAction地址,当然还有服务方法的名称,返回类型,参数列表。这里,我们省略掉服务方法的参数列表,构造代理类,实际上就是一个字符串组装的问题,先创建一个类型,用于保存构造代理类所要用到的参数: 服务代理类构造参数
[u]复制代码[/u] 代码如下:
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
[u]复制代码[/u] 代码如下:
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 : ClientBase<IRuntimeService>, 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方法:
[u]复制代码[/u] 代码如下:
 public override int GetHashCode()   {       return String.Concat(serviceNamespace, methodAction, methodReplyAction, methodName, returnType).GetHashCode();   }
然后在WebServiceProxyCreator中加入缓存机制:
[u]复制代码[/u] 代码如下:
  public class WebServiceProxyCreator    {        private static Dictionary<int, Type> proxyTypeCatch = new Dictionary<int, 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;       }  }
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部