设计模式学习——动态代理实现C#动态调用WebService(附源码)

目前创新互联已为上千家的企业提供了网站建设、域名、雅安服务器托管、网站托管维护、企业网站设计、宁城网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。

对于这个问题,很很早以前就遇到了,当时并不理解。前段时间看了一下动态代理,对这个问题有了一些了解。

对于一般的webservice,可以通过添加web引用实现调用。但这样的缺点就是不够灵活,当webservice地址发生变化时需要重新添加引用,重新编译。这种缺点还稍微可以接受的。我遇到的应用场景是,程序运行之前无法知道webservice的地址,因为地址都存放于数据库中,使用时需要动态的调用。这样通过添加引用基本不可能实现,所以采用上述方法实现。

在采用这种方法时,首先遇到的问题就是:如何构造的代理类?

类似于java中JDK提供的有编译源文件的接口,.net也提供的有相关的类似的我们能够动态的生成源码并进行编译,从而动态的生成代理类。(当然不排除大牛通过解析语法规则直接生成二进制文件,而无需调用编译接口的。)

我们可以采用类似于下面的方法来动态的生成要编译的源码。

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, "", "");  

    CodeNamespace nmspace = new CodeNamespace();

       nmspace.Name = "WebService";//生成类的名空间,可以根据需求指定

       CodeCompileUnit unit = new CodeCompileUnit();

       unit.Namespaces.Add(nmspace);

       ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);

       return unit;

   }

Unit返回的就是要进行编译的东西了。

 

下一步及时进行编译了。根据需求设置相关的编译参数后,就就可以进行编译了。就像下边这样。

 

 

 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;

   }

 

有了编译的结果,已经生成了代理类,下一步要做的就是将这个代理类加载到内存当中。

  Assembly asm = result.CompiledAssembly;

       object obj = asm.CreateInstance("WebService." + proxy._className);

这样就将代理类加载到了内存当中,并且长生了一个实例,将这个实例返回就可以根据他来调用所需的方法了。当然调用方法时可能还是要用到反射,因为已知的可能仅仅只有方法名和它所需的参数。

更多详细内容请查看本文源码。

附件:http://down.51cto.com/data/2358642

分享标题:设计模式学习——动态代理实现C#动态调用WebService(附源码)
网页地址:http://pwwzsj.com/article/iehscs.html