深夜写完的代码——快速实现.NET(.net framework/.net core+)动态访问webservice服务

前言:访问webservice,大多数人都是用服务引用的方式,但是这种方式比较麻烦,例如遇到服务更新了,你还需要手动更新你的服务引用,再重新发布,很麻烦。或者已有的一些例子,至少我看到的很多案例,动态访问也只能止步于使用.net framework环境,没看到有啥.net core上面动态访问的案例。于是我就来抛砖引玉一下,自己写一个支持.net framework也可以支持.netcore或以上环境使用的动态访问webservice服务接口的方法,供大家使用或参考。

先创建一个webservice服务,用来测试使用。提供三个服务接口,一个无参数、一个字符串参数、一个含有多个实体类参数(实体类参数也含有嵌套和集合)以及返回带有嵌套和集合的返回数据,用来做测试使用,基本上可以涵盖几乎所有的webservice服务的情况了。

b9b565ad9fd7373a568dbb3c5696ecbb.png

有关测试实体类

fa2a11b1aef824c8215a84bc992f9350.png

启动webservice服务备用

30f5d0da8ce056bfbb840d9155c9aca4.png

请求端程序,支持.netframework 4.6.1+、.net core+和.net 5+所有版本,都可以通过nuget来引用 Wesky.Net.OpenTools 包。需要引用最新的版本,以保证功能完善。我此处使用.net 8的控制台来引用,大佬们可以根据自己程序情况进行引用,framework4.6以下版本不适用。

6e89ec4d31bf088e65ef46f0c4f11aa0.png

为了方便使用,我本地也直接编写几个实体类,用来传参和做返回值接收使用:

4d5ef5fedf65aef2c88fd25708fc9d22.png

先实例化一个WebserviceHelper对象,如果有用IOC容器的大佬,比如说使用asp.net core程序等,可以对该接口和类进行依赖注入的注册。如果没用IOC容器的大佬,可以直接这样new一个使用。此处我用new一个对象的使用方式来使用。并且获取到asmx的url地址,地址此处需要添加?wsdl后缀。

ea41dbb19197efc13128dbce5371bcc4.png

申明要访问的服务的名称,例如HelloWorld,然后直接调用。由于没有参数,所以参数直接设为null

5985a7e3d5b9bad2a89a25c7bdebd544.png

运行程序进行调用,可以看到获取到了返回值的xml文档。

52a1b47fd6bf55aa5383e0e0a6477d3e.png

直接调用的时候,返回值是一个 OpenToolResult类型,类型定义如下:

6cb1d09675e6b1ac01b9bca575b46dde.png

由于咱们的返回值就一个基础类型string,所以需要调用解析基础类型值的方法,得到最终的返回消息为 Hello World。

1c4914c2348f7750616b29dcf36cee83.png

基础类型值解析方法定义如下:

cf0a1b0f1634c7fd4994978036c6f9ee.png

传入参数为:获取到的返回值、节点名称(一般是方法名称+“Result”)、命名空间,命名空间在调用的时候,会被存储到类型OpenWebserviceInfo的属性OpenWebservice集合(是一个OpenWebserviceDocCache类型的集合)里面去,通过url地址和接口方法名字可以匹配到对应的命名空间。

OpenWebserviceDocCache类型定义如下:

32b6b8954a573d6f1161445bffb0cdbe.png

接着试一下传入一个基础类型参数的情况。访问Hola方法,传入Wesky字符串,成功获取到返回值 Wesky World。

4d0f7135c20fad31352a578fcdd4575a.png

接下来试一下传入多个实体类参数,并且按照上面webservice的内容,会返回一个其他一个实体类消息。

cda4fbf7c45664e8f3cfb9799775ba4b.png

回看一下TestService服务接口的实现,说明动态访问是成功的。

ce7a4e40e7934f59f8333083b7caa43e.png

访问webservice方法定义说明。参数可以传0个或多个参数,会用来和解析度wsdl地址的同名方法服务参数个数做匹配,如果不匹配,则会提示错误信息。返回值Result.IsSuccess如果是true,代表发送请求成功;如果解析错误或者发送请求失败等,则提示false,并且Message属性会有具体错误信息描述。

fc22735c6443ab86d583e62bd1ca4201.png

返回值为实体类的解析方法定义说明。以上请求TestSevice服务接口时候,返回值是实体类,如果需要匹配本地的实体类,需要访问 ExtractCustomerValueFromXml方法进行解析处理。例如上面传入的是ResultInfo类型作为返回值接收类。

3c74a6e8232f7d0a4b168a28f7eb619d.png

一些核心代码:

/// <summary>
  /// 调用Web服务
  /// Calls a web service.
  /// </summary>
  /// <param name="url">服务URL / Service URL</param>
  /// <param name="apiName">API名称 / API name</param>
  /// <param name="expireSecond">过期时间(秒)/ Expiration time in seconds</param>
  /// <param name="parameters">调用参数 / Invocation parameters</param>
  /// <returns>调用结果 / Invocation result</returns>
  public OpenToolResult<string> CallWebservice(string url, string apiName,long expireSecond = 86400,params object[] parameters)
  {
      OpenToolResult<string> result = new HttpExtensions.OpenToolResult<string>();


      CheckExpireTime(url, apiName, expireSecond);


      var wsInfo = OpenWebserviceInfo.OpenWebservice.FirstOrDefault(x => x.WebserviceUrl == url && x.OperationName == apiName);


      if (wsInfo == null)
      {
          result.IsSuccess = false;
          result.Message = "本地无法加载远程webservice服务。Cannot load the remote webservice locally.";
          return result;
      }


      if ((parameters == null && wsInfo.ParameterNames.Count > 0) || (parameters!=null && parameters.Length != wsInfo.ParameterNames.Count))
      {
          result.IsSuccess = false;
          result.Message = $"远程服务接口参数个数和你传入的参数个数不匹配。远程服务参数个数:{wsInfo.ParameterNames.Count}, 本地传入参数个数:{parameters?.Length ?? 0}。Parameter count mismatch: remote service has {wsInfo.ParameterNames.Count}, provided {parameters?.Length ?? 0}.";
          return result;
      }




      Dictionary<string, string> dicParams = new Dictionary<string, string>();
      if (parameters != null)
      {
          for (int i = 0; i < wsInfo.ParameterNames.Count; i++)
          {
              dicParams.Add(wsInfo.ParameterNames[i], XmlConvertor.SerializeObjectToXml(parameters[i]));
          }
      }
      var response = InvokeService(url, apiName, dicParams,wsInfo.Namespace);


      result.Result = response;
      result.IsSuccess = true;
      result.Message = "success";


      return result;
  }

如果以上内容对你有帮助,欢迎点赞、转发、在看和关注我的个人公众号:【Dotnet Dancer】

如果需要以上演示代码和webservice测试源码,可以在公众号【Dotnet Dancer】后台回复“动态接口”进行下载。

OpenTools系列文章快捷链接【新版本完全兼容旧版本,不需要更新任何代码均可使用】:

1.0.11版本

如何一行C#代码实现解析类型的Summary注释(可用于数据字典快速生成)

https://mp.weixin.qq.com/s/CWqubRRMoYVQIQJSyjIUXg

1.0.10版本:

C#/.NET一行代码把实体类类型转换为Json数据字符串

https://mp.weixin.qq.com/s/nVcURD0lf5-AQOVzwHqcxw

1.0.8版本:

上位机和工控必备!用.NET快速搞定Modbus通信的方法

https://mp.weixin.qq.com/s/Yq6kuXzFglHfNUqrHcQO9w

1.0.7版本:

大揭秘!.Net如何在5分钟内快速实现物联网扫码器通用扫码功能?

https://mp.weixin.qq.com/s/-5VuLAS6HlElgDQXRY9-BQ

1.0.6版本:

.NET实现获取NTP服务器时间并同步(附带Windows系统启用NTP服务功能)

https://mp.weixin.qq.com/s/vMW0vYC-D9z0Dp6HFSBqyg

1.0.5版本:

C#使用P/Invoke来实现注册表的增删改查功能

https://mp.weixin.qq.com/s/LpsjBhDDzkwyLU_tIpF-lg

1.0.3版本:

C#实现图片转Base64字符串,以及base64字符串在Markdown文件内复原的演示

https://mp.weixin.qq.com/s/n9VtTCIiVUbHJk7OfoCcvA

1.0.2版本:

C#实现Ping远程主机功能(支持IP和域名)

https://mp.weixin.qq.com/s/d-2HcIM1KaLo-FrrTLkwEw

1.0.1版本:

开始开源项目OpenTools的创作(第一个功能:AES加密解密)

https://mp.weixin.qq.com/s/78TA-mst459AuvAHwQViqQ

【备注】包版本完全开源,并且没有任何第三方依赖。使用.net framework 4.6+、任意其他跨平台.net版本环境,均可直接引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值