在 .NET 环境下访问 SOAP 服务
在 .NET 环境下访问 SOAP 服务
SOAP 服务有着悠久的历史,目前仍然存在大量的 SOAP 服务,它是基于 HTTP 协议和 XML 技术的简单对象访问协议。
在 .NET Framework 时代,访问 SOAP 服务还是比较方便的,我们既可以使用 wsdl.exe 这个工具,也可以使用集成在 Visual Studio 的项目中的工具来生成服务代理,这个代理需要添加对 System.WebService 程序集的引用,它派生自 System.Web.Services.Protocols.SoapHttpClientProtocol,帮助我们访问 SOAP 服务。
在 .NET 时代,很多时候我们仍然需要访问现存的 SOAP 服务,使用的工具和所基于的库发生了一些变化。
首先,我们需要获取 SOAP 服务的定义 通常我们可以通过访问某个服务端点来获得它,对于大多数的 SOAP 服务来说,它会有一个 WSDL 的部分。例如,微软报表服务的管理端点就是 https://myserver/ReportServer/ReportService2010.asmx?wsdl ,也可以通过访问此类端点并保存获得的 WSDL 到一个文件中。
我们这里就使用这个 Reporting Service 2010 进行说明。
如果你希望使用交互工具的话,Visual Studio 中提供了集成的 使用 WCF Web Service Reference Provider 工具。你可以在项目上点击右键,选择 Add -> Connected Service,然后在 Service Reference (OpenAPI, gRPC, WCF Web Service) 的卡片上点击 + 来添加。后面的步骤与以前的工具就是一致的。
如果你希望自己完成,那请继续和我们一起前进。
第二步,安装用于 .NET 的 dotnet-svcutil NuGet 包。
dotnet tool install --global dotnet-svcutil
直接执行它可以看到如下输出
> dotnet-svcutil
Microsoft (R) WCF Service Model Proxy Generation Tool for .Net Core platform
[Microsoft.Tools.ServiceModel.Svcutil, Version 2.1.0]
Copyright (c) Microsoft Corporation. All rights reserved.
This tool collects information about how it is used in order to improve the tool. This functionality can be disabled by setting the environment variable "DOTNET_SVCUTIL_TELEMETRY_OPTOUT" to 1.
Error: No valid input specified. Specify either a service url or a wsdl file.
If you would like more help, type "dotnet-svcutil -h"
and
minimum supported framework versions are as follows: netcoreapp1.0, netstandard1.3 and net4.5.
执行安装的 dotnet-svcutil 来生成客户端代理。
dotnet-svcutil https://<Server Name>/ReportServer/ReportService2010.asmx?wsdl
第三步,生成了什么
针对我们使用的 ReportingService201 来说,首先工具帮我们生成了访问该服务的接口 ReportingService2010Soap
public interface ReportingService2010Soap
{
// ...
}
实现该接口的类型 ReportingService2010SoapClient
public partial class ReportingService2010SoapClient : System.ServiceModel.ClientBase<ServiceReference.ReportingService2010Soap>, ServiceReference.ReportingService2010Soap
{
// ...
}
需要注意的是该类是一个分部类 partial 类。这意味着我们可以在自己的代码中定义另外一部分,以对生成类进行扩展。
在类定义的第一部分是一个特殊的分部方法 ConfigureEndpoint。方法的注释中这样说:
实现此分部方法以配置此服务端点。
在后面看到的生成的构造函数中,会调用此方法。所以,我们可以在自定义的分部类中,定义实际的此方法来配置该 Web 服务端点。
/// <summary>
/// Implement this partial method to configure the service endpoint.
/// </summary>
/// <param name="serviceEndpoint">The endpoint to configure</param>
/// <param name="clientCredentials">The client credentials</param>
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
同时,该类还提供了 4 个构造函数。其中前面的 3 个都会调用这个 ConfigureEndpoint() 方法来配置端点。但是,最后一个没有调用这个方法。
public ReportingService2010SoapClient(EndpointConfiguration endpointConfiguration) :
base(ReportingService2010SoapClient.GetBindingForEndpoint(endpointConfiguration), ReportingService2010SoapClient.GetEndpointAddress(endpointConfiguration))
{
this.Endpoint.Name = endpointConfiguration.ToString();
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
}
public ReportingService2010SoapClient(EndpointConfiguration endpointConfiguration, string remoteAddress) :
base(ReportingService2010SoapClient.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress))
{
this.Endpoint.Name = endpointConfiguration.ToString();
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
}
public ReportingService2010SoapClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) :
base(ReportingService2010SoapClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress)
{
this.Endpoint.Name = endpointConfiguration.ToString();
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
}
public ReportingService2010SoapClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
在项目中,需要添加下面的 NuGet 包
<ItemGroup>
<PackageReference Include="System.ServiceModel.Http" Version="4.10.*" />
<PackageReference Include="System.ServiceModel.Security" Version="4.10.*" />
</ItemGroup>
第 4 步,使用生成的代理
我们通过使用第 4 个构造函数来访问这个服务。
Reporting Service 使用的是基本的 SOAP 服务,同时使用 Windows 验证进行保护。所以使用 BasicHttpBinding,并配置 Ntlm 认证协议。
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
TimeSpan timeout = TimeSpan.FromMinutes(5);
binding.OpenTimeout = timeout;
binding.CloseTimeout = timeout;
binding.SendTimeout = timeout;
binding.ReceiveTimeout = timeout;
配置访问端点
String endpointurl = "http://myserver/ReportServer/reportservice2010.asmx";
EndpointAddress endpoint = new EndpointAddress(endpointurl);
var service = new ReportingService2010SoapClient(binding, endpoint);
配置客户端的 Windows 认证账号
service.ClientCredentials.Windows.ClientCredential.UserName = "username";
service.ClientCredentials.Windows.ClientCredential.Password = "password";
service.ClientCredentials.Windows.ClientCredential.Domain = "domain";
好了,现在就可以访问服务了。
第 5 步,使用自定义的分部类来创建 Soap 的客户端
通过上面的介绍,可以看到创建一个客户端实例还是要做一些细致的准备的。我们可以通过自定义的分部类来封装这一部分,通过提供一个扩展出来的方法 GetSoapClientInstance() 来直接获得此实例。
public partial class ReportingService2010SoapClient
{
public static ReportingService2010SoapClient GetSoapClientInstance() {
String endpointurl = "http://apxse07.advent.com/ReportServer/reportservice2010.asmx";
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
TimeSpan timeout = TimeSpan.FromMinutes(5);
binding.OpenTimeout = timeout;
binding.CloseTimeout = timeout;
binding.SendTimeout = timeout;
binding.ReceiveTimeout = timeout;
EndpointAddress endpoint = new EndpointAddress(endpointurl);
var service = new ReportingService2010SoapClient(binding, endpoint);
service.ClientCredentials.Windows.ClientCredential.UserName = "Axyssu";
service.ClientCredentials.Windows.ClientCredential.Password = "June25!!";
service.ClientCredentials.Windows.ClientCredential.Domain = "Advent";
return service;
}
}
这样,我们可以使用下面的代码来得到一个客户端代理的实例:
var soapClient = ReportingService2010SoapClient.GetSoapClientInstance();
第 6 步,访问 Reporting Service 2010 获得服务器上的文件列表。
在 Reporting Service 上包含多种资源,Report 只是其中的一种。Reporting Service 的 SOAP 服务提供了通用的方法 FindItems(),可以定义一个通用的方法来支持获得资源的列表。
方法需要两个参数:一个是资源的类型,一个是目标文件夹。
在生成的代码中,已经包含了请求 SOAP 服务的 Request 定义和 Response 定义,我们需要使用它们来访问 SOAP 服务。
private string[] GetAllOfType(string typeName, string folder)
{
SearchCondition[] conditions = new SearchCondition[0];
Property[] options = new Property[0];
FindItemsRequest request = new FindItemsRequest();
request.Folder = folder;
request.BooleanOperator = BooleanOperatorEnum.And;
request.SearchOptions = options;
request.SearchConditions = conditions;
FindItemsResponse response = this.FindItems(request);
CatalogItem[] items = response.Items;
List<string> itemNames = new List<string>();
if (items != null)
foreach (CatalogItem ci in items)
if (ci.TypeName == typeName)
itemNames.Add(ci.Name);
return itemNames.ToArray();
}
在创建了 GetAllOfType() 方法之后,我们可以编写获得服务器上部署的报表列表了。
public string[] GetAllReports(string folder)
{
return GetAllOfType("Report", folder);
}
参考资料
- WCF dotnet-svcutil tool for .NET Core
- SAP PO SOAP Web Service with .NET Core client
- The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'Negotiate, NTLM'
在 .NET 环境下访问 SOAP 服务的更多相关文章
- Windows环境下访问NFS(33篇Storage的文章)
Windows环境下访问NFS 使用Solaris时,如果想在两台Solaris之间共享数据,那么你想到的最省事.最方便的方法肯定是nfs.但是现在的学生们的桌面,估计99%以上都是Windows,W ...
- 在Mac OS环境下安装MySQL服务
在Mac OS环境下安装MySQL服务 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我之前介绍过window环境下安装mysql服务,以及在Linux环境下安装mysql服务,今 ...
- ubuntu 14.04LTS 环境下配置NFS服务
简言之,NFS(Network FileSystem,网络文件系统)用于在不同机器,不同操作系统之间通过网络互相分享各自的文件.NFS设计之初就是为了在不同的系统间使用,所以它的通讯协议设计与主机及操 ...
- 【高并发】高并发环境下构建缓存服务需要注意哪些问题?我和阿里P9聊了很久!
写在前面 周末,跟阿里的一个朋友(去年晋升为P9了)聊了很久,聊的内容几乎全是技术,当然了,两个技术男聊得最多的话题当然就是技术了.从基础到架构,从算法到AI,无所不谈.中间又穿插着不少天马行空的想象 ...
- 【swoole】如何在docker+swoole环境下测试udp服务
前面几篇文章讲了使用 docker+swoole 环境来测试tcp服务以及如何测试,但是当我开始学习udp服务那块的时候,发现使用原来的方式在 docker+swoole 环境下行不通啦,后来发现如果 ...
- 项目部署到liunx环境下访问接口返回异常
1.访问接口返回异常 已经连续踩了两次这个坑了.所以记下来了.方便下次搜索! 项目在window下运行正常,无任何异常! 但是部署到liunx环境下的服务器上就有问题 访问静态页面毫无问题,一旦涉及到 ...
- Python 访问soap服务
使用库:subs soap服务信息: 网址:http://mobile.bjmemc.com.cn/AirService/Service.asmx 功能:使用其中的GetData服务获取北京各个地点的 ...
- LNMP环境下搭建SVN服务
最近自己买了个服务器,试着在上面搭建了LNMP环境,因为以前在本地用MAMP Pro搭建过LAMP环境,所以基本上还算是轻车熟路,第一次搭建LNMP,使用的是一键安装,过程是顺利的,后来在使用过程中遇 ...
- Docker容器启动lnmp环境下的mysql服务时报"MySQL server PID file could not be found"错误解决办法
我在自己的mac笔记本上装了一个docker,并在docker容器中安装了lnmp环境,经常会遇到在使用"lnmp restart"命令启动lnmp服务的时候,mysql服务启动失 ...
- Centos7 环境下开机 自启动服务(service) 设置的改变 (命令systemctl 和 chkconfig用法区别比较)
参考文章: <Linux 设置程序开机自启动 (命令systemctl 和 chkconfig用法区别比较)> http://blog.csdn.net/kenhins/article/ ...
随机推荐
- 三大硬核方式揭秘:Java如何与底层硬件和工业设备轻松通信!
大家好,我是V哥,程序员聊天真是三句不到离不开技术啊,这不前两天跟一个哥们吃饭,他是我好多年前的学员了,一直保持着联系,现在都李总了,在做工业互联网相关的项目,真是只要 Java 学得好,能干一辈子, ...
- Android应用启动全流程分析(源码深度剖析)
目录 1.前言 2.大纲 3. Input触控事件处理流程 3.1 系统机制分析 3.2 结合Systrace分析 4. 应用进程的创建与启动 4.2 创建应用进程 4.2.1 AMS 发送socke ...
- Android 12 关机重启流程
1. 关机流程 Android上层触发关机的入口很多,但最终几乎都是调用ShutdownThread.shutdown来实现.如下是一些常见的调用关机的点: StatusBarManagerServi ...
- 技术分享 | 徐轶韬:从MySQL5.7升级到MySQL 8.0
在6月20日举办的[墨天轮数据库沙龙-MySQL 5.7 停服影响与应对方案]中,甲骨文MySQL解决方案首席工程师徐轶韬分享了<从MySQL5.7升级到MySQL 8.0>主题演讲,本文 ...
- excel导⼊功能的实现流程简要描述⼀下?
当时公司的场景⼤概⼀个excel⽂件⾥就⼏⼗条数据,量⽐较少,和后端商量之后制定了前端主导的⽅ 案,解析的过程放到了浏览器端做,当时是参考了⼀下vue-admin中的现成的⽅案 ⼤概流程是这样的,⼈事 ...
- Vue中mixins(混入)的介绍和使用
为什么引进 mixins 随着项目的开发,组件越来越多 ,这就导致了在各个组件中需要编写功能相同的代码段,重复地定义这些相同的属性和方法,导致代码地冗余,还不利于后期代码的维护 混入mixins 的创 ...
- kotlin类和对象—>接口
1.接口定义,使用关键字interface 来定义接口 interface MyInterface { fun bar() fun foo() { // 可选的方法体 } } 2.实现接口,一个类和对 ...
- Android复习(六)核心组件—>Activity 简介、生命周期、状态变更
1. 可以在activity上声明权限,来保证只在进入某个activity是否有某种权限 <manifest> <activity android:name="....&q ...
- p1ngp0ng
p1ngp0ng 轻量级ICMP C2工具 依赖 Linux环境与GCC套件. 功能: p1ng: p1ng,实现C2服务器正向连接被控端.目前实现了对客户端的命令控制与文件上传下载.明文传输,未加密 ...
- java截取##间的话题字符串
转载MARK一下,百度根据关键字不好搜到,省的下次到处找.package iqiyi.com.model;import java.util.regex.Matcher;import java.util ...