第三方公司一般使用Java、C#或者其他语言以wsdl的方式发布Web服务供我们使用,但在C#调用端不允许使用VS添加服务引用的方式进行调用(因为服务的url地址有可能经常变动,需要存储在数据库中进行维护),这种动态调用的方式就派上用场了。
需要添加System.Web.Services.dll的引用
代码如下:
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web.Services.Description;
using System.Xml.Serialization;
namespace WpfDemo1
{
class WcfHelper
{
/// <summary>
/// WebService服务代理
/// </summary>
public class WebServiceProxy
{
/// <summary>
/// 命名空间
/// </summary>
private string ClassName = null;
/// <summary>
/// WebServiceURL地址
/// </summary>
private string WebServiceUrl { get; set; }
/// <summary>
/// WebService服务代理构造方法
/// </summary>
/// <param name="webServiceUrl">WebServiceURL地址</param>
private WebServiceProxy(string webServiceUrl)
{
this.WebServiceUrl = webServiceUrl + "?WSDL";
this.ClassName = webServiceUrl.Substring(webServiceUrl.LastIndexOf('/') + 1);
this.ClassName = ClassName.Substring(0, ClassName.LastIndexOf('.'));
}
/// <summary>
/// 根据编译结果生成实例并返回
/// </summary>
/// <param name="webServiceUrl">WebServiceURL地址</param>
/// <returns>根据编译结果生成实例并返回</returns>
public static object CreateInstance(string webServiceUrl)
{
WebServiceProxy proxy = new WebServiceProxy(webServiceUrl);
CodeCompileUnit unit = proxy.GetServiceCompileUnit(proxy.WebServiceUrl);
CompilerResults result = proxy.Compile(unit);
Assembly asm = result.CompiledAssembly;
return asm.CreateInstance("WebService." + proxy.ClassName);
}
/// <summary>
/// 获得CodeDOM 程序图形容器
/// </summary>
/// <param name="webServiceUrl">WebServiceURL地址</param>
/// <returns>获得CodeDOM 程序图形容器</returns>
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, "", ""); //添加WSDL文档。
CodeNamespace nmspace = new CodeNamespace(); //命名空间
nmspace.Name = "WebService";
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nmspace);
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
return unit;
}
/// <summary>
/// 编译
/// </summary>
/// <param name="unit">CodeDOM 程序图形容器</param>
/// <returns>返回从编译器返回的编译结果</returns>
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;
}
/// <summary>
/// Web服务调用
/// </summary>
/// <param name="webServiceUrl">服务URL</param>
/// <param name="methodName">服务方法名称</param>
/// <param name="parameters">方法参数</param>
/// <returns></returns>
public static object Invoke(string webServiceUrl, string methodName, object[] parameters)
{
if (string.IsNullOrEmpty(webServiceUrl))
throw new Exception("WebService的URL地址为空!");
if (string.IsNullOrEmpty(methodName))
throw new Exception("WebService的方法名为空!");
object instance = WebServiceProxy.CreateInstance(webServiceUrl);
MethodInfo method = instance.GetType().GetMethod(methodName);
return method.Invoke(instance, parameters);
}
}
}
}
调用:WebServiceProxy.Invoke("WebService的URL地址","WebService的方法名","方法的参数");
最重要的是编译wsdl,然后使用反射技术进行动态调用
注意:WebService的URL地址不带?wsdl,如果没有方法的参数,还得自己使用反射的技术进行处理