前言站在开发者的角度,WebService技术确实是不再“时髦”。甚至很多人会说,我们不再用它。当然,为了使软件可以更简洁,更有层次,更易于实现缓存等机制,我是非常建议将SOAP转为RESTful架构风格的。但到目前为止,WebService在一些PublicInstitution中使用还是十分广泛的。这里主要讨论一下关于WebService的调用问题。关于WebService的调用分为静态调用和动态调用两种。静态调用静态调用的方式是通过“AddServiceReference...”创建客户端代理类。这种方式让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务。这样是使工作简单了,但是却将提供Web服务的URL、方法名、参数绑定在一起了,这是VS.NET自动为我们生成Web服务代理的限制。如果发布Web服务的URL改变了,则我们需要重新让VS.NET生成代理,并重新编译。很常见的一个场景,某银行Web服务,因为部署的URL更改,而不得不去重新编译生成代理,这将会带来很多不必要的工作量。如果我们使用动态调用就可以避免这种情况。关于静态调用,不是这篇文章的重点,故不作详细介绍。动态调用在某些情况下我们需要在程序运行期间动态调用一个服务。在.NETFramework的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信息并创建代理类的程序集。1publicclassWSHelper2{3///summary4///输出的dll文件名称5////summary6privatestaticstringm_OutputDllFilename;78///summary9///WebService代理类名称10////summary11privatestaticstringm_ProxyClassName;1213///summary14///WebService代理类实例15////summary16privatestaticobjectm_ObjInvoke;1718///summary19///接口方法字典20////summary21privatestaticDictionaryEMethod,MethodInfom_MethodDic=newDictionaryEMethod,MethodInfo();2223///summary24///创建WebService,生成客户端代理程序集文件25////summary26///paramname=error错误信息/param27///returns返回:true或false/returns28publicstaticboolCreateWebService(outstringerror)29{30try31{32error=string.Empty;33m_OutputDllFilename=ConfigurationManager.AppSettings[OutputDllFilename];34m_ProxyClassName=ConfigurationManager.AppSettings[ProxyClassName];35stringwebServiceUrl=ConfigurationManager.AppSettings[WebServiceUrl];36webServiceUrl+=?WSDL;3738//如果程序集已存在,直接使用39if(File.Exists(Path.Combine(Environment.CurrentDirectory,m_OutputDllFilename)))40{41BuildMethods();42returntrue;43}4445//使用WebClient下载WSDL信息。46WebClientweb=newWebClient();47Streamstream=web.OpenRead(webServiceUrl);4849//创建和格式化WSDL文档。50if(stream!=null)51{52//格式化WSDL53ServiceDescriptiondescription=ServiceDescription.Read(stream);5455//创建客户端代理类。56ServiceDescriptionImporterimporter=newServiceDescriptionImporter57{58ProtocolName=Soap,59Style=ServiceDescriptionImportStyle.Client,60CodeGenerationOptions=61CodeGenerationOptions.GenerateProperties|CodeGenerationOptions.GenerateNewAsync62};6364//添加WSDL文档。65importer.AddServiceDescription(description,null,null);6667//使用CodeDom编译客户端代理类。68CodeNamespacenmspace=newCodeNamespace();69CodeCompileUnitunit=newCodeCompileUnit();70unit.Namespaces.Add(nmspace);7172ServiceDescriptionImportWarningswarning=importer.Import(nmspace,unit);73CodeDomProviderprovider=CodeDomProvider.CreateProvider(CSharp);7475CompilerParametersparameter=newCompilerParameters76{77GenerateExecutable=false,78//指定输出dll文件名。79OutputAssembly=m_OutputDllFilename80};8182parameter.ReferencedAssemblies.Add(System.dll);83parameter.ReferencedAssemblies.Add(System.XML.dll);84parameter.ReferencedAssemblies.Add(System.Web.Services.dll);85parameter.ReferencedAssemblies.Add(System.Data.dll);8687//编译输出程序集88CompilerResultsresult=provider.CompileAssemblyFromDom(parameter,unit);8990//使用Reflection调用WebService。91if(!result.Errors.HasErrors)92{93BuildMethods();94returntrue;95}96else97{98error=反射生成dll文件时异常;99}100stream.Close();101stream.Dispose();102}103else104{105error=打开WebServiceUrl失败;106}107}108catch(Exceptionex)109{110error=ex.Message;111}112returnfalse;113}114115///summary116///反射构建Methods117////summary118privatestaticvoidBuildMethods()119{120Assemblyasm=Assembly.LoadFrom(m_OutputDllFilename);121//vartypes=asm.GetTypes();122TypeasmType=asm.GetType(m_ProxyClassName);123m_ObjInvoke=Activator.CreateInstance(asmType);124125//varmethods=asmType.GetMethods();126varmethods=Enum.GetNames(typeof(EMethod)).ToList();127foreach(variteminmethods)128{129varmethodInfo=asmType.GetMethod(item);130if(methodInfo!=null)131{132varmethod=(EMethod)Enum.Parse(typeof(EMethod),item);133m_MethodDic.Add(method,methodInfo);134}135}136}137138///summary139///获取请求响应140////summary141///paramname=method方法/param142///paramname=para参数/param143///returns返回:Json串/returns144publicstaticstringGetResponseString(EMethodmethod,paramsobject[]para)145{146stringresult=null;147if(m_MethodDic.ContainsKey(method))148{149vartemp=m_MethodDic[method].Invoke(m_ObjInvoke,para);150if(temp!=null)151{152result=temp.ToString();153}154}155returnresult;156}157}调用接口。1//SOAP请求响应方式2TextBox3.Text=WSHelper.GetResponseString(EMethod.Add,Convert.ToInt32(TextBox1.Text),Convert.ToInt32(TextBox2.Text));Http请求除了静态调用和动态调用,我们还可以发送HttpPost请求来调用WebService的方法。Soap请求就是HTTPPOST的一个专用版本,遵循一种特殊的xml消息格式。使用HttpPost请求,对返回结果我们可以手动解析。下面的实现其实和调用WebAPI是完全一样的。1///summary2///请求信息帮助3////summary4publicpartialclassHttpHelper