.Net core 调用WebService

在REST出现之前解决跨平台之间的通信问题基本都是采用基于XML的WebService进行。

一、什么是WebService

Web Service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的交互操作的应用程序。 .

Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。Web Service是自描述、 自包含的可用网络模块, 可以执行具体的业务功能。Web Service也很容易部署, 因为它们基于一些常规的产业标准以及已有的一些技术,诸如标准通用标记语言下的子集XML、HTTP。Web Service减少了应用接口的花费。Web Service为整个企业甚至多个组织之间的业务流程的集成提供了一个通用机制。

二、Net Framwork调用WebService

在.Net Framwork上调用WebService有一整套的构架支持,其中主要的有:1、直接引用式。即在VS中“添加服务引用”,然后输入服务地址后确定,最后会生成服务所对应的动态代理类,之后的所有调用将基于该代理类,跟正常的调用类方法一样。该方式简单快速,但前提是要有服务且服务可用,但往往在开发这种跨平台的服务调用时基本上都第三方,并且是第三方一般先前只会提供对应的服务接口文档,不会有实际可用的服务,需待到调试阶段对会有服务可用,同时当服务后需变化时又需重新引用生成新的代理类,适应变化能力差。

2、动态代理方式。该方法通过反射机制动态的获取并生成服务的代理。该方式灵活,不会因为服务的变化而变更修改代码,只需知道服务的接口方法和相关参数即可。主要代码:

 public static void CreateWebServiceDLL(string url, string className, string methodName, string filePath)
{
// 1. 使用 WebClient 下载 WSDL 信息。
WebClient web = new WebClient();
//Stream stream = web.OpenRead(url + "?WSDL");
CertificateTrust.SetCertificatePolicy();//证书出现问题时调用此代码//未能为 SSL/TLS 安全通道建立信任关系
Stream stream = web.OpenRead(url);
// 2. 创建和格式化 WSDL 文档。
ServiceDescription description = ServiceDescription.Read(stream);
//如果不存在就创建file文件夹
if (Directory.Exists(filePath) == false)
{
Directory.CreateDirectory(filePath);
}
if (File.Exists(filePath + className + "_" + methodName + ".dll"))
{
//判断缓存是否过期
var cachevalue = HttpRuntime.Cache.Get(className + "_" + methodName);
if (cachevalue == null)
{
//缓存过期删除dll
File.Delete(filePath + className + "_" + methodName + ".dll");
}
else
{
// 如果缓存没有过期直接返回
return;
}
}
// 3. 创建客户端代理代理类。
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
// 指定访问协议。
importer.ProtocolName = "Soap";
// 生成客户端代理。
importer.Style = ServiceDescriptionImportStyle.Client;
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
// 添加 WSDL 文档。
importer.AddServiceDescription(description, null, null);
// 4. 使用 CodeDom 编译客户端代理类。
// 为代理类添加命名空间,缺省为全局空间。
CodeNamespace nmspace = new CodeNamespace();
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nmspace);
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameter = new CompilerParameters();
parameter.GenerateExecutable = false;
// 可以指定你所需的任何文件名。
parameter.OutputAssembly = filePath + className + "_" + methodName + ".dll";
parameter.ReferencedAssemblies.Add("System.dll");
parameter.ReferencedAssemblies.Add("System.XML.dll");
parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
parameter.ReferencedAssemblies.Add("System.Data.dll");
// 生成dll文件,并会把WebService信息写入到dll里面
CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
if (result.Errors.HasErrors)
{
// 显示编译错误信息
System.Text.StringBuilder sb = new StringBuilder();
foreach (CompilerError ce in result.Errors)
{
sb.Append(ce.ToString());
sb.Append(System.Environment.NewLine);
}
throw new Exception(sb.ToString());
}
//记录缓存
var objCache = HttpRuntime.Cache;
// 缓存信息写入dll文件
objCache.Insert(className + "_" + methodName, "1", null, DateTime.Now.AddMinutes(5), TimeSpan.Zero, CacheItemPriority.High, null);
}
}
}
(2)调用方法,前面四个配置信息可以写在app.config里,也可以直接代码里写死。
/// <param name="xml">要上传的参数</param>
private void UseWebService(string xml)
{
// 读取配置文件,获取配置信息
string url = ConfigurationManager.AppSettings["WebServiceAddress"];//WebService地址
string className = ConfigurationManager.AppSettings["ClassName"];//WebService提供的类名
string methodName = ConfigurationManager.AppSettings["MethodName"];// WebService方法名
string filePath = ConfigurationManager.AppSettings["FilePath"];//存放dll文件的地址
// 调用WebServiceHelper
WebServiceHelper.CreateWebServiceDLL(url, className, methodName, filePath);
// 读取dll内容
byte[] filedata = File.ReadAllBytes(filePath + className + "_" + methodName + ".dll");
// 加载程序集信息
Assembly asm = Assembly.Load(filedata);
Type t = asm.GetType(className);
// 创建实例
object o = Activator.CreateInstance(t);
MethodInfo method = t.GetMethod(methodName);
// 参数
object[] args = {xml};
// 调用访问,获取方法返回值
string value = method.Invoke(o, args).ToString();
//输出返回值
MessageBox.Show($"返回值:{value}");
}

三、Net Core 调用WebService

 在.NET Core上调用WebService目前没有将.NET Framwork上的那种动态代理的方式继承下来,故而不可直接使用。那如何调用呢?网上有各种各样的方式,其中有一种方式:

var parameters= new Dictionary<string, string>
{
{ "para1", objData},
{ "para2", "test" },
};
HttpContent httpContent = new FormUrlEncodedContent(parameters);
// contentType对应 webservice提示 如下图
httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = httpClient.PostAsync("https://localhost:44329/WebService1.asmx/HelloWorld", httpContent).Result;
var statusCode = response.StatusCode.ToString();
var result = response.Content.ReadAsStringAsync().Result;
var doc = new XmlDocument();
doc.LoadXml(result);
// xml返回值数据所在标签,替换成你的xml结果标签,如下图
var status = doc.DocumentElement["Status"].InnerXml;

该方式是所见的最常用的一种,他的确也可行,但这个可行只能用于WebService服务是即.Net平台编写的服务,但是当服务是另外语言编写的时即不可行,不信可以试试,反正我是试过。

那要如何调用基于其他语言编写的呢,如Java。我也遇到过该问题,在经过多次的尝试后都不成功,后面又转头仔细地想了想,WebSerice的最核心协议是什么啊?哦,是基于SOAP协议的,再对SOAP协议进行了详细的了解后,最后终于解决了问题。废话就不多说了,直接上源代码吧,这样更清楚。

HttpClient httpClient = new HttpClient() { };
StringBuilder contentString = new StringBuilder();
String meothName="Hello";   //服务的方法名
Dictionary<string, object> args= new Dictionary<string, object>() ; //方法的参数
args["content"]="您好";
foreach (var item in args)
{
  contentString.Append($"<{item.Key}><![CDATA[{item.Value}]]></{item.Key}>");
}
 string contentValue = contentString.ToString();
 string content = $@"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
                   <soapenv:Body>
                     <{meothName} xmlns=""http://tempuri.org/"">
                         {contentValue}
                     </{meothName}>
                 </soapenv:Body>
              </soapenv:Envelope>";
 HttpContent   httpContent = new StringContent(content, Encoding.UTF8, "text/xml");
HttpResponseMessage response = httpClient.PostAsync(uri, extends.httpContent).Result;
  var result = response.Content.ReadAsStringAsync().Result; //得到返回的结果,注意该结果是基于XML格式的,最后按照约定解析该XML格式中的内容即可。