创建方法
.net Framework
using Microsoft.CSharp;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
namespace HealthyCardPostApp.Helper
{
public class WebServiceHelper
{
// 用Dictionary保存已经反射生成过的WebService和Method,省去每次调用都重新生成实例
#region 动态调用WebService
/// <summary>
/// WebService服务列表
/// </summary>
private static ConcurrentDictionary<string, object> ServiceDictionary = new ConcurrentDictionary<string, object>();
/// <summary>
/// WebService Method方法列表
/// </summary>
private static ConcurrentDictionary<string, System.Reflection.MethodInfo> MethodDictionary = new ConcurrentDictionary<string, System.Reflection.MethodInfo>();
/// <summary>
/// 动态调用WebService(开发环境ping不通需要调用的WebService地址时使用)
/// </summary>
/// <param name="url">webservice地址</param>
/// <param name="methodName">需要调用的方法名称</param>
/// <param name="param">调用上方法时传入的参数</param>
/// <returns>执行方法后返回的数据</returns>
public static async Task<object> InvokeWebService(string url, string methodName, string[] param)
{
try
{
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(methodName))
{
return null;
}
url = url.ToLower().EndsWith("wsdl") ? url : (url + "?WSDL");
// 检查是否已经存在WebService服务 和 方法
string key = url + methodName;
if (!ServiceDictionary.ContainsKey(key) || !MethodDictionary.ContainsKey(key))
{
//客户端代理服务命名空间,可以设置成需要的值。
string space = string.Format("ProxyServiceReference");
//获取WSDL
WebClient webClient = new WebClient();
Stream stream = webClient.OpenRead(url);
ServiceDescription description = ServiceDescription.Read(stream);//服务的描述信息都可以通过ServiceDescription获取
string classname = description.Services[0].Name;
ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
descriptionImporter.AddServiceDescription(description, "", "");
CodeNamespace codeNamespace = new CodeNamespace(space);
//生成客户端代理类代码
CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
codeCompileUnit.Namespaces.Add(codeNamespace);
descriptionImporter.Import(codeNamespace, codeCompileUnit);
CSharpCodeProvider provider = new CSharpCodeProvider();
//设定编译参数
CompilerParameters comilerParameters = new CompilerParameters();
comilerParameters.GenerateExecutable = false;
comilerParameters.GenerateInMemory = true;
comilerParameters.ReferencedAssemblies.Add("System.dll");
comilerParameters.ReferencedAssemblies.Add("System.XML.dll");
comilerParameters.ReferencedAssemblies.Add("System.Web.Services.dll");
comilerParameters.ReferencedAssemblies.Add("System.Data.dll");
//编译代理类
CompilerResults compilerResult = provider.CompileAssemblyFromDom(comilerParameters, codeCompileUnit);
if (compilerResult.Errors.HasErrors == true)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (System.CodeDom.Compiler.CompilerError ce in compilerResult.Errors)
{
sb.Append(ce.ToString());
sb.Append(System.Environment.NewLine);
}
throw new Exception(sb.ToString());
}
//生成代理实例,并调用方法
System.Reflection.Assembly assembly = compilerResult.CompiledAssembly;
Type service = assembly.GetType(space + "." + classname, true, true);
if (!ServiceDictionary.ContainsKey(key))
{
object wsInstance = Activator.CreateInstance(service);
//((SoapHttpClientProtocol)wsInstance).Timeout = int.MaxValue;
//部分url会改变,重新赋值
//((SoapHttpClientProtocol)wsInstance).Url = url.Replace("?wsdl", "");
ServiceDictionary.TryAdd(key, wsInstance);
}
System.Reflection.MethodInfo SSOServiceMethod = service.GetMethod(methodName);
MethodDictionary.TryAdd(key, SSOServiceMethod);
}
return await Task.Run(() => {
return MethodDictionary[key].Invoke(ServiceDictionary[key], param);
});
}
catch (Exception ex)
{
LogHelper.LogError<WebServiceHelper>($"调用服务时发生错误:{url} {methodName} {string.Join(",", param)}\n{ex}");
return null;
}
}
#endregion
}
}
.net6
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Linq;
public static class WebServiceHelper
{
/// <summary>
/// 动态调用 ASMX WebService
/// </summary>
/// <param name="url">asmx 地址</param>
/// <param name="methodName">方法名</param>
/// <param name="parameters">参数名=值</param>
/// <param name="muti">多个结果值</param>
public static async Task<object> InvokeAsync(string url, string methodName, Dictionary<string, string>? parameters = null, bool muti = false)
{
if (string.IsNullOrWhiteSpace(url))
throw new ArgumentNullException(nameof(url));
if (string.IsNullOrWhiteSpace(methodName))
throw new ArgumentNullException(nameof(methodName));
// 1. 构造 SOAP 请求
string soapXml = BuildSoapXml(methodName, parameters);
// 2. 发送请求
using var client = new HttpClient();
var content = new StringContent(soapXml, Encoding.UTF8, "text/xml");
var response = await client.PostAsync(url, content);
response.EnsureSuccessStatusCode();
// 3. 解析 SOAP 响应
string xml = await response.Content.ReadAsStringAsync();
return ExtractResult(xml, methodName, muti);
}
public static object InvokeAsync(string v1, string v2, Dictionary<string, string> dictionary, object[] objects)
{
throw new NotImplementedException();
}
#region Private Methods
private static string BuildSoapXml(string method, Dictionary<string, string>? parameters)
{
var sb = new StringBuilder();
sb.AppendLine(@"<?xml version=""1.0"" encoding=""utf-8""?>");
sb.AppendLine(@"<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" ");
sb.AppendLine(@"xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" ");
sb.AppendLine(@"xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">");
sb.AppendLine("<soap:Body>");
sb.AppendLine($"<{method} xmlns=\"http://tempuri.org/\">");
if (parameters != null)
{
foreach (var p in parameters)
{
sb.AppendLine($"<{p.Key}>{p.Value}</{p.Key}>");
}
}
sb.AppendLine($"</{method}>");
sb.AppendLine("</soap:Body>");
sb.AppendLine("</soap:Envelope>");
return sb.ToString();
}
private static object ExtractResult(string soapXml, string methodName, bool muti)
{
var doc = new XmlDocument();
doc.LoadXml(soapXml);
var ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
if (muti)
{
var nodes = doc.SelectNodes($"//soap:Body/*[local-name()='{methodName}Response']/*[local-name()='{methodName}Result']", ns);
List<string> result = new List<string>();
foreach (XmlNode node in nodes)
{
result.Add(node?.InnerText ?? string.Empty);
}
return result;
}
else
{
var node = doc.SelectSingleNode($"//soap:Body/*[local-name()='{methodName}Response']/*[local-name()='{methodName}Result']", ns);
return node?.InnerText ?? string.Empty;
}
}
#endregion
}
方法使用
使用InvokeWebService 方法时注意事项:
1、入参只需要传数据值,不需要带Web Service的入参名称
2、如果Web Service的有多个入参,需要注意入参顺序
3、如果入参类型为xml,考虑用<![CDATA[]]>封装(如果CDATA封装后报错xml格式错误,则不需要使用CDATA封装)
WebServiceHelper.InvokeWebService("http://xxxxx:xx/xxxWebServices.asmx",
"方法名",
new object[] { "字符串入参1", "<![CDATA[xml入参2]]>" });
本文介绍了一种在C#中动态调用WebService的方法,通过反射生成WebService客户端代理类,并提供了具体的实现代码。该方法适用于开发环境中无法直接访问WebService的情况。

438

被折叠的 条评论
为什么被折叠?



