动态调用WebService接口的几种方式-程序员宅基地

技术标签: Web 接口开发系列  web service  

一、什么是WebService?

 这里就不再赘述了,想要了解的====》传送门

二、为什么要动态调用WebService接口?

一般在C#开发中调用webService服务中的接口都是通过引用过来就行调用的,步骤如下:

1.找到引用,右击添加服务引用,找到高级,添加web引用,添加之后就可以直接调用里面的方法。

 

以上这种方法是最简单粗暴的一种方式。当然在开发中总是不那么如意,以上方式是在本机直接可以访问服务的地址,假如在本机不能直接访问WebService,那么就会有些蛋疼。

这种方式就不可取了,那么有什么方式可以不直接访问就可以开发呢?这就要使用动态调用的方式进行调用了。接下来就是如何动态调用WebService了。

三、动态调用WebService的几种方式

 方式一:

随便百度一下就可以找到的一种,接下了的代码来源于百度找到的并性能进行优化升级过。

public static class CommonServiceHelper
    {
        /// <summary>
        /// 静态缓存字典,速度提升至8倍
        /// </summary>
        private static Dictionary<string, object> _webServiceConfig = new Dictionary<string, object>();

        //获取WSDL
        private static readonly WebClient wc = new WebClient();

        /// < summary>
        /// 动态调用web服务
        /// </summary>
        /// < param name="url">WSDL服务地址</param>
        /// < param name="classname">类名</param>
        /// < param name="methodname">方法名</param>
        /// < param name="args">参数</param>
        /// < returns></returns>
        public static object InvokeWebService(this string url, string methodname, object[] args, string classname = "")
        {
            string key = $"{url}_{methodname}";//缓存Key唯一标识
            Type webService;
            if (!_webServiceConfig.ContainsKey(key))
            {
                string @namespace = "EnterpriseServerBase.WebService.DynamicWebCalling";
                //classname 一般自己指定 如果有些地址是http://www.webxml.com.cn/WebServices/WeatherWS?wsdl 就会调用失败
                if ((classname == null) || (classname == ""))
                {
                    classname = GetWsClassName(url);
                }
                try
                {
                    Stream stream = wc.OpenRead(url);
                    ServiceDescription sd = ServiceDescription.Read(stream);
                    ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
                    sdi.AddServiceDescription(sd, "", "");
                    CodeNamespace cn = new CodeNamespace(@namespace);
                    CodeCompileUnit ccu = new CodeCompileUnit();
                    ccu.Namespaces.Add(cn);
                    sdi.Import(cn, ccu);
                    CSharpCodeProvider icc = new CSharpCodeProvider();
                    CompilerParameters cplist = new CompilerParameters
                    {
                        GenerateExecutable = false,
                        GenerateInMemory = true
                    };
                    cplist.ReferencedAssemblies.Add("System.dll");
                    cplist.ReferencedAssemblies.Add("System.XML.dll");
                    cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
                    cplist.ReferencedAssemblies.Add("System.Data.dll");
                    CompilerResults compiler = icc.CompileAssemblyFromDom(cplist, ccu);
                    icc.Dispose();
                    if (compiler.Errors.HasErrors)
                    {
                        System.Text.StringBuilder sb = new System.Text.StringBuilder();
                        foreach (CompilerError ce in compiler.Errors)
                        {
                            sb.Append(ce.ToString());
                            sb.Append(Environment.NewLine);
                        }
                        throw new Exception(sb.ToString());
                    }
                    System.Reflection.Assembly assembly = compiler.CompiledAssembly;
                    Type t = assembly.GetType(@namespace + "." + classname, true, true);
                    webService = t;
                    _webServiceConfig.Add(key, webService);//加入缓存
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
            else
            {
                webService = _webServiceConfig[key] as Type;//获取缓存的数据
            }
            if (webService != null)
            {
                object obj = Activator.CreateInstance(webService);
                System.Reflection.MethodInfo mi = webService.GetMethod(methodname);
                if (mi != null)
                {
                    return mi.Invoke(obj, args);
                }
                throw new Exception($"找不到{methodname}这个方法,调用失败");
            }
            else
            {
                throw new Exception($"WebService 对象为空,调用失败");
            }
        }

        /// <summary>
        /// 获取wsdl类名称
        /// </summary>
        /// <param name="wsUrl">wsdl地址</param>
        /// <returns></returns>
        private static string GetWsClassName(string wsUrl)
        {
            string[] parts = wsUrl.Split('/');
            string[] pps = parts[parts.Length - 1].Split('.');//classname 一般自己指定 原因是因为在这里
            return pps[0];
        }
        /// <summary>
        /// 清空缓存
        /// </summary>
        public static void ClearCache()
        {
            _webServiceConfig.Clear();
        }
    }

 

 以上方法是第一种,这种方法不是万能的,因为方法是通过反射调用的,多个参数的时候顺序不能乱,方法名称不能写错,对于有些WebService是无法调用的。

方式二:

这种方式针对本机不能访问的WebService非常有效,参数啥的不容易搞混,跟C#直接添加引用之后调用方式一样。

C#添加引用的方式是通过对于WebService的xml进行解析并生成相关代码,根据原理可知,只要有WebService的xml就好办了。

对于本机不能访问的WebService,找个可以访问的环境,用浏览器进行访问,后面加上wsdl,例如:http://www.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl

然后进行访问,把页面另存为你可以找得到的地方。我这里直接存储到D盘

把这个xml文件丢到你本地随便一个可以访问的的站点下,这个xml文件要可以正常访问。(这个很重要)

 接下来就要使用visual studio 开发人员命令工具,我这里是使用vs2019 ,前面几个版本的vs都可以

在开始菜单里面找到并打开

 接下来使用命令生成代码。

命令如下:wsdl  你本地访问的那个xml地址全路径                                     

我这里是放在端口81的站点下

生成的cs类文件跟通过web引用生成的cs文件是一样,这样就可以解决本机不能直接访问WebService不能调用方法的问题。

当然,想要可以执行其中的方法还需要把代码放到对应环境上才能执行。

四、总结

以上是使用两种方式动态调用WebService接口的方式,在实际开发中,遇到不能访问的,一般用第二种比较保险。

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39237340/article/details/118751233

智能推荐

鸿蒙系统可以替代安卓吗,华为今天发布的鸿蒙系统,到底能不能替代安卓?-程序员宅基地

文章浏览阅读570次。对于大部分差友们来说,“开发者大会”这个词一定显得陌生而又遥远,跟普通的产品发布会不一样,他们面向的对象并不是普通的消费者,而是各种程序猿和攻城狮。话又说回来,能开“ 开发者大会”,也说明这个企业已经牛逼到了一定程度。。譬如每年的谷歌开发者大会,苹果的WWDC 都受到超多人关注,因为千千万万开发者就是依靠着安卓和iOS 生态创造价值,它们的任何更新和变动都引领着未来互联网的走向。这种会议完全是企业..._华为鸿蒙系统能代替安卓吗

Linux运行jar包命令_linux执行jar包命令带参数-程序员宅基地

文章浏览阅读1.4w次,点赞2次,收藏23次。一. linux下运行jar包的命令1、java -jar xxxxx.jar // 当前xshell窗口被锁定,可按CTRL + C打断程序运行,或直接关闭窗口,程序退出2、java -jar xxxxx.jar & //当前shell窗口不被锁定,但是当窗口关闭时,程序中止运行。3、nohup Java -jar xxxxxx.jar & //意思是不挂断运行命令,当账户退出或终端关闭时,程序仍然运行二. 下面详细介绍第三种运行方式/*下面介绍如何关闭第三种运行的jar包程序/_linux执行jar包命令带参数

C#LeetCode刷题之#344-反转字符串​​​​​​​(Reverse String)_c#将任意字符串反转输出-程序员宅基地

文章浏览阅读1.2w次。问题编写一个函数,其作用是将输入的字符串反转过来。输入: "hello"输出: "olleh"输入: "A man, a plan, a canal: Panama"输出: "amanaP :lanac a ,nalp a ,nam A"Write a function that takes a string as input and returns the str..._c#将任意字符串反转输出

实现游戏数据文件读取和写入_游戏data文件怎么编辑-程序员宅基地

文章浏览阅读1.6k次。前言 关于代码与文件交互方式的选择,基本常用的有以下三种,与txt格式的文本文件交互,与ini格式的配置文件交互,与xml类型的文件交互。考虑到交互数据为游戏数据,因此采用第3种。文本利用C#的正反序列化技术来实现游戏数据文件的读取和写入。准备工作 本人使用的开发环境为VisualStudio2019..._游戏data文件怎么编辑

hive if 用法-程序员宅基地

文章浏览阅读4.2w次,点赞6次,收藏20次。1.If函数:if和case差不多,都是处理单个列的查询结果语法: if(boolean testCondition, T valueTrue, T valueFalseOrNull)返回值: T说明:当条件testCondition为TRUE时,返回valueTrue;否则返回valueFalseOrNull举例:if(条件表达式,结果1,结果2)相当于java中的三目运算符..._hive if

如何做好腾讯视频号?腾讯视频号的机会!_腾讯视频号服务外包怎么做-程序员宅基地

文章浏览阅读1k次。腾讯扩大了视频号的内测范围,很多的朋友都收到了视频号的邀请,每个人都觉得视频号是一个创业的契机,最起码站在了风口的边缘,似乎明天注册公司,后天就能出任CEO迎接白富美了。对于视频号的这个机会,很不好意思,我先帮您泼一盆冷水,没有正确的追风的姿势,最后还是安然离场! 历来的风口,抓住了哪个? 从微博到公众号,从公众号到头条,从头条到抖音,每一次都是一个机会,现在看看很多人还不是一样,看..._腾讯视频号服务外包怎么做

随便推点

信号完整性之阻抗匹配与端接方法_传输线的阻抗匹配和端接方式-程序员宅基地

文章浏览阅读9.4k次,点赞15次,收藏98次。信号完整性之阻抗匹配与端接方法1. 前言随着电子技术的发展,电路的规模越来越大,单个器件集成的功能越来越多,速率越来越高,而器件的尺寸越来越小。由于器件尺寸的减小,器件引脚信号变化沿的速率变得越来越高,导致SI问题越来越突出。SI (Signal Integrity,信号完整性)与以下几个因素有关:反射、串扰、辐射。反射是由信号传输路径上的阻抗不连续造成的;串扰与信号的间距有关;辐射则与高速器件自身以及PCB设计均有关。2. 信号的阻抗匹配信号的阻抗匹配是影响信号完整性最主要的._传输线的阻抗匹配和端接方式

Ae 入门系列之一:了解 Ae 及工作流程-程序员宅基地

文章浏览阅读1.7k次,点赞2次,收藏5次。Adobe After Efftects(简称为 Ae )可以帮助用户高效且精确地创建无数种引人注目的动态图形和震撼人心的视觉效果,利用与其他 Adobe 软件紧密集成和高度灵活的二维和三..._ae视频渲染从入门到精通 csdn

Android进程间通信--消息机制及IPC机制实现_ipc机制和消息机制-程序员宅基地

文章浏览阅读479次。Android为了屏蔽进程的概念,利用不同的组件[Activity、Service]来表示进程之间的通信!组件间通信的核心机制是Intent,通过Intent可以开启一个Activity或Service,不论这个Activity或Service是属于当前应用还是其它应用的! _ipc机制和消息机制

mysql中文编码问题-程序员宅基地

文章浏览阅读38次。我比较推荐的方法是在创建数据库时便设置中文编码create database bp default character set utf8; #注意是utf8不是utf-8以下方法只适用于mysql5.5以上版本的(其实我的是mariadb5.5版本的) 编辑mysql配置文件[root@localhost ~]# cat /etc/my.cnf..._群晖 mysql5.6 中文乱码

HRNet提取骨架特征点+ ST-GCN训练自己的数据集代码实践问题记录-程序员宅基地

文章浏览阅读1w次,点赞12次,收藏140次。软硬件环境:python 3.6.5Ubuntu 18.04 LTSPytorch 1.1.0NVIDIA TITAN XP 8GB项目链接https://github.com/open-mmlab/mmskeleton准备工作先准备数据集准备环境,包含两步:第一步: 进入文件夹./deprecated/origin_stgcn_repo/ ,打开requirements.txt看下需要满足的环境条件,conda list:我不直接安装requirements.txt中的需求原因是,_hrnet提取骨架

分支限界法TSP问题-程序员宅基地

文章浏览阅读1.7k次。分支限界法TSP问题//分支限界法#include<iostream>#include<algorithm>#include<cstdio>#include<queue>const int INF = 100000;const int MAX_N = 22;using namespace std;//n*n的一个矩阵int n;int cost[MAX_N][MAX_N];//最少3个点,最多MAX_N个点struct Node{