C# WebService动态调用
标签:
C# WebService动态调用 前言站在开发者的角度,WebService 技术确实是不再“时髦”。甚至很多人会说,我们不再用它。当然,为了使软件可以更简洁,更有层次,更易于实现缓存等机制,我是非常建议将 SOAP 转为 RESTful 架构风格的。但到目前为止,WebService 在一些Public Institution 中使用还是十分广泛的。
这里主要讨论一下关于WebService的调用问题。关于WebService 的调用分为静态调用和动态调用两种。
静态调用静态调用的方式是通过“Add Service Reference...”创建客户端代理类。这种方式让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务。这样是使工作简单了,但是却将提供Web服务的URL、方法名、参数绑定在一起了,这是VS.NET自动为我们生成Web服务代理的限制。如果发布Web服务的URL改变了,则我们需要重新让VS.NET生成代理,并重新编译。很常见的一个场景,某银行Web服务,因为部署的URL更改,而不得不去重新编译生成代理,这将会带来很多不必要的工作量。如果我们使用动态调用就可以避免这种情况。关于静态调用,不是这篇文章的重点,故不作详细介绍。
动态调用在某些情况下我们需要在程序运行期间动态调用一个服务。在 .NET Framework 的 System.Web.Services.Description 命名空间中有我们需要的东西。动态调用有动态调用 WebService、生成客户端代理程序集文件、生成客户端代理类源代码3种方式。
动态调用的具体步骤为:
1)从目标 URL 下载 WSDL 数据;
2)使用 ServiceDescription 创建和格式化 WSDL 文档文件;
3)使用 ServiceDescriptionImporter 创建客户端代理类;
4)使用 CodeDom 动态创建客户端代理类程序集;
5)利用反射调用相关 WebService 方法。
第一种方式通过在内存中创建动态程序集的方式完成了动态调用过程;第二种方式将客户端代理类生成程序集文件保存到硬盘,然后可以通过 Assembly.LoadFrom() 载入并进行反射调用。对于需要多次调用的系统,要比每次生成动态程序集效率高出很多;第三种方式是保存源码文件到硬盘中,然后再进行反射调用。
这里将只讨论第二种方式,这种方式也是我们在实际应用中最常用的。这种方式只下载 一次 WSDL 信息并创建代理类的程序集。往后程序每次启动都会反射之前创建好的程序集。如果是 Web服务 URL 变更,只需要修改 App.config 中的 WebServiceUrl 和 ProxyClassName 配置项,并将程序根目录下生成的程序集删除即可。下次程序启动又会重新下载WSDL信息并创建代理类的程序集。
App.config文件。
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <appSettings> 4 <!--WebService地址--> 5 <add key="WebServiceUrl" value="http://localhost:25060/testService/" /> 6 <!--WebService输出dll文件名称--> 7 <add key="OutputDllFilename" value="TestWebService.dll" /> 8 <!--WebService代理类名称--> 9 <add key="ProxyClassName" value="TestService" /> 10 </appSettings> 11 </configuration>
创建代理类。
1 public class WSHelper 2 { 3 /// <summary> 4 /// 输出的dll文件名称 5 /// </summary> 6 private static string m_OutputDllFilename; 7 8 /// <summary> 9 /// WebService代理类名称 10 /// </summary> 11 private static string m_ProxyClassName; 12 13 /// <summary> 14 /// WebService代理类实例 15 /// </summary> 16 private static object m_ObjInvoke; 17 18 /// <summary> 19 /// 接口方法字典 20 /// </summary> 21 private static Dictionary<EMethod, MethodInfo> m_MethodDic = new Dictionary<EMethod, MethodInfo>(); 22 23 /// <summary> 24 /// 创建WebService,生成客户端代理程序集文件 25 /// </summary> 26 /// <param>错误信息</param> 27 /// <returns>返回:true或false</returns> 28 public static bool CreateWebService(out string error) 29 { 30 try 31 { 32 error = string.Empty; 33 m_OutputDllFilename = ConfigurationManager.AppSettings["OutputDllFilename"]; 34 m_ProxyClassName = ConfigurationManager.AppSettings["ProxyClassName"]; 35 string webServiceUrl = ConfigurationManager.AppSettings["WebServiceUrl"]; 36 webServiceUrl += "?WSDL"; 37 38 // 如果程序集已存在,直接使用 39 if (File.Exists(Path.Combine(Environment.CurrentDirectory, m_OutputDllFilename))) 40 { 41 BuildMethods(); 42 return true; 43 } 44 45 //使用 WebClient 下载 WSDL 信息。 46 WebClient web = new WebClient(); 47 Stream stream = web.OpenRead(webServiceUrl); 48 49 //创建和格式化 WSDL 文档。 50 if (stream != null) 51 { 52 // 格式化WSDL 53 ServiceDescription description = ServiceDescription.Read(stream); 54 55 // 创建客户端代理类。 56 ServiceDescriptionImporter importer = new ServiceDescriptionImporter 57 { 58 ProtocolName = "Soap", 59 Style = ServiceDescriptionImportStyle.Client, 60 CodeGenerationOptions = 61 CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync 62 }; 63 64 // 添加 WSDL 文档。 65 importer.AddServiceDescription(description, null, null); 66 67 //使用 CodeDom 编译客户端代理类。 68 CodeNamespace nmspace = new CodeNamespace(); 69 CodeCompileUnit unit = new CodeCompileUnit(); 70 unit.Namespaces.Add(nmspace); 71 72 ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); 73 CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); 74 75 CompilerParameters parameter = new CompilerParameters 76 { 77 GenerateExecutable = false, 78 // 指定输出dll文件名。 79 OutputAssembly = m_OutputDllFilename 80 }; 81 82 parameter.ReferencedAssemblies.Add("System.dll"); 83 parameter.ReferencedAssemblies.Add("System.XML.dll"); 84 parameter.ReferencedAssemblies.Add("System.Web.Services.dll"); 85 parameter.ReferencedAssemblies.Add("System.Data.dll"); 86 87 // 编译输出程序集 88 CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit); 89 90 // 使用 Reflection 调用 WebService。 91 if (!result.Errors.HasErrors) 92 { 93 BuildMethods(); 94 return true; 95 } 96 else 97 { 98 error = "反射生成dll文件时异常"; 99 } 100 stream.Close(); 101 stream.Dispose(); 102 } 103 else 104 { 105 error = "打开WebServiceUrl失败"; 106 } 107 } 108 catch (Exception ex) 109 { 110 error = ex.Message; 111 } 112 return false; 113 } 114 115 /// <summary> 116 /// 反射构建Methods 117 /// </summary> 118 private static void BuildMethods() 119 { 120 Assembly asm = Assembly.LoadFrom(m_OutputDllFilename); 121 //var types = asm.GetTypes(); 122 Type asmType = asm.GetType(m_ProxyClassName); 123 m_ObjInvoke = Activator.CreateInstance(asmType); 124 125 //var methods = asmType.GetMethods(); 126 var methods = Enum.GetNames(typeof(EMethod)).ToList(); 127 foreach (var item in methods) 128 { 129 var methodInfo = asmType.GetMethod(item); 130 if (methodInfo != null) 131 { 132 var method = (EMethod)Enum.Parse(typeof(EMethod), item); 133 m_MethodDic.Add(method, methodInfo); 134 } 135 } 136 } 137 138 /// <summary> 139 /// 获取请求响应 140 /// </summary> 141 /// <param>方法</param> 142 /// <param>参数</param> 143 /// <returns>返回:Json串</returns> 144 public static string GetResponseString(EMethod method, params object[] para) 145 { 146 string result = null; 147 if (m_MethodDic.ContainsKey(method)) 148 { 149 var temp = m_MethodDic[method].Invoke(m_ObjInvoke, para); 150 if (temp != null) 151 { 152 result = temp.ToString(); 153 } 154 } 155 return result; 156 } 157 }
调用接口。
温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/68110.html
- 上一篇:ASP.NET WebAPI 01
- 下一篇:Win7另存文件没有桌面的解决方法