C#静态/动态调用webservice(JSON参数传递)

背景:
这边需要用C#call一个webservice的接口,推过去的参数以JSON的格式传递过去。
说实话,接口写了很多,全部是封装好的,直接调用,把对象传进去就好了,所以要写个从无到有的,有点蒙蔽,只能百度自己查了。

1.接口调用地址验证
拿到人家的接口,首先要验证接口是否正确。
在这里插入图片描述
在浏览器中输入该地址:返回结果如下,正常返回,能看到里面所有方法
C#静态/动态调用webservice(JSON参数传递)_第1张图片
2.验证调用方法是否正确
刚开始我用postman,按照百度,输入request地址,选择post方式,在Headers中配置“Content-Type”等,结果点击send之后,返回的记过就是soap:Fault,没办法,主要是postman里面设置的东西太多了,估计我哪项没设置好导致无法正确读取我传过去的参数,然后百度又百度不到怎么设置参数的。
然后改用SoapUI就可以了,官网下载SoapUI,安装完毕运行,新建SOAP项目:
C#静态/动态调用webservice(JSON参数传递)_第2张图片
随便起个名称TEST,然后在Initial WSDL中输入刚才在浏览器中验证的接口地址,点击OK
C#静态/动态调用webservice(JSON参数传递)_第3张图片
在左侧菜单栏中,可以看到此接口的所有16个方法,与浏览器中看到的一致
C#静态/动态调用webservice(JSON参数传递)_第4张图片
选择你需要call的方法双击Request1,将直接跳出你需要传输过去的XML,里面包含了需要填入的2个参数。
但是我被接口方给的接口文档混淆了,文档上写传过去的必须是JSON格式,百度了好久,都找不到WebService传参传Json的例子,全是传XML的,后来才知道,WebService传参就是以XML格式传过去的,即使文档里面说的JSON格式,实际上也是一个JSON格式的字符串放在XML的参数里而已。
如下,文档说传过去的参数必须是JSON格式,所实际上就是在 < paras>?中放入JSON格式的字符串。
然后又遇到一个问题, < ValidateData>?是什么鬼?接口文档中压根没有,所以只能绕N久找到接口的给出方问了,这个应该是对应验证XML的一个参数,只要传固定值就好了(总结经验,call接口必须得找给出接口的人,面对面测试,否则自己肯兹肯兹半天都不一定搞得出来,这边就是,文档中就压根没给出ValidateData的参数)
C#静态/动态调用webservice(JSON参数传递)_第5张图片
写入2个参数,第一个参数跟接口方讨论了下,是固定值;第二个参数就是按照接口文档给出的规范,传过去一个JSON类型的字符串,输入2个参数,点击运行,可以看到,调用接口方法后正确返回结果。
C#静态/动态调用webservice(JSON参数传递)_第6张图片

3.接口调用方法正确后,开始写代码如何调用该方法了。
网上查了下C#调用webService接口的方式有3种方式,看下面链接,写的很详细:(但是动态调用我按照他里面写的,就是无法调用,代码走到调用生成的.dll文件一直是null,不知道为啥)
https://www.jb51.net/article/190211.htm

因为要测试代码,所以我先随便建立了一个“Windows窗体应用程序”,随便添加个button,在点击事件里面来走下代码测试下结果:
3.1.静态调用
静态调用最简单,如果是给定接口的URL(即我这边的案例),直接引用即可
刚开始我以为静态调用无法更改url地址,实际上并不是,在静态引用后,vs会很智能的自动将地址配置到配置文件中,这时候更改url地址,即配置文件中的地址了。
右击引用,选择添加服务引用
C#静态/动态调用webservice(JSON参数传递)_第7张图片
将给的接口地址输入,点击“转到”,则可以看到“服务”中的接口了,然后自己修改个命名空间即可,注:有些接口文档给出的地址可能需要自己补上尾部“?WSDL”
C#静态/动态调用webservice(JSON参数传递)_第8张图片
然后你回看到引用的接口已经被添加到项目中,类似于一个类文件,或者说就可以把“ServiceReference1”看做一个封装好的接口类就行了
C#静态/动态调用webservice(JSON参数传递)_第9张图片
双击ServiceReference1,可以看到所有的方法都在里面
C#静态/动态调用webservice(JSON参数传递)_第10张图片
找到方法名
C#静态/动态调用webservice(JSON参数传递)_第11张图片
双击方法名,进入“Reference.cs”文件,们可以看到里面的所有方法了。
然后找到实现该方法名的真正方法“WebBuilderWebServiceForZTBClient”
C#静态/动态调用webservice(JSON参数传递)_第12张图片
实例化那个接口类:“接口类名.方法名”。
最后根据接口文档,调用业务方法“client.InformationDel(validateData, paras);”。
C#静态/动态调用webservice(JSON参数传递)_第13张图片
针对“client.InformationDel(validateData, paras);”,我们按F12进入到“Reference.cs”文件,可以看到InformationDel()删除方法与上面我们用SoapUI测试的传入参数是一致的
C#静态/动态调用webservice(JSON参数传递)_第14张图片
与SoapUI测试的输入XML参数一致,也是2个参数:“ValidateData”和“paras”C#静态/动态调用webservice(JSON参数传递)_第15张图片
点击button完成点击事件,可以看到输出结果是成功的,传过来也是JSON字符串,需要的话,可以直接把它转成对象。
C#静态/动态调用webservice(JSON参数传递)_第16张图片
最后我们在“Reference.cs”文件里面,拉倒最上面可以看到,里面有个“ConfigurationName”下面的方法全部按照这个方法名来调用的,这个实际上就是vs自动智能帮忙生成的配置文件的Url
C#静态/动态调用webservice(JSON参数传递)_第17张图片
进入配置文件,可以看到自动配置好的地址,如果ip变了,只要配置这边就OK了,无需重新生成引用文件了
C#静态/动态调用webservice(JSON参数传递)_第18张图片
3.2.动态调用
刚开始我以为静态调用是接口地址固定调用,而动态调用时接口地址变动的调用,但是实际上,静态调用也是可以配置地址的,如3.1最后写的一点,实际上静态调用指的是直接引用接口地址,动态调用是代码生成的.dll文件,然后引用该文件,实现dll中的类,调用里面的方法。
根据百度的参考,就是调用不起来,尝试了不同的人写的都不行,最后没法办了只好采用静态调用,直到写这个笔记之前,想找到原因,然后又找了个人写的,居然可以了,发现可能是@namespace命名的问题,同样的方法,我按照下面这位博主的方法,就调用成功了,看了下好像就@namespace命名不同,其他都一样。
https://www.cnblogs.com/ruochen/archive/2007/12/11/990427.html
直接上代码,就是上面的连接

 private void button7_Click(object sender, EventArgs e)
        {

            string validateData = "epointoa@83OZsT5IdXL2uwu_XMvEfpdpzrc=@MjE0NzQ4MzY0Nw==";
            string paras = "[" +
                            "{" +
                                "'siteGuid': '123'," +
                                "'infoId': 'SCJG20990040'," +
                            "}" +
                        "]";

            //这里的namespace是需引用的webservices的命名空间,在这里是写死的,大家可以加一个参数从外面传进来。
            string @namespace = "client";
            try
            {

               string url= "http://192.168.0.1:8081/EpointWebBuilder/services/WebBuilderWebServiceForZTB";
                //获取WSDL
                WebClient wc = new WebClient();
                Stream stream = wc.OpenRead(url + "?WSDL");
                ServiceDescription sd = ServiceDescription.Read(stream);
                string classname = sd.Services[0].Name;
                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 csc = new CSharpCodeProvider();
                ICodeCompiler icc = csc.CreateCompiler();

                //设定编译参数
                CompilerParameters cplist = new CompilerParameters();
                cplist.GenerateExecutable = false;
                cplist.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 cr = icc.CompileAssemblyFromDom(cplist, ccu);
                if (true == cr.Errors.HasErrors)
                {
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();
                    foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
                    {
                        sb.Append(ce.ToString());
                        sb.Append(System.Environment.NewLine);
                    }
                    throw new Exception(sb.ToString());
                }

                //生成代理实例,并调用方法
                System.Reflection.Assembly assembly = cr.CompiledAssembly;
                Type t = assembly.GetType(@namespace + "." + classname, true, true);
                object obj = Activator.CreateInstance(t);
                System.Reflection.MethodInfo mi = t.GetMethod("InformationDel");

                object obj1 = mi.Invoke(obj, new object[] { validateData, paras });
                MessageBox.Show($"方法返回值:{obj1.ToString()}"); 输出
                
            }
            catch (Exception ex)
            {
                string expt = ex.ToString();
            }
        }

结果也一样成功了
C#静态/动态调用webservice(JSON参数传递)_第19张图片
4.查看接口方结果。
完成以上3步,实际上OK了,需要查看的就是对方接口功能是否正确。
坑爹的就是,明明返回true,但是接口的业务就是没有完成,无法看到预期结果。
最后还是找对方,联合测试,对方查看,返回true是因为数据已经成功插入到他们的数据库了,但是业务没完成,是因为里面的“地区”字段传空了,那边不知道把内容关联到哪个地区,所有没有显示最终结果。我只能表示“呵呵”了,既然“地区”字段必须要有值,那你接口文档为何要写允许为空?关键还是返回true?
C#静态/动态调用webservice(JSON参数传递)_第20张图片
5.总结
即使接口文档写的很详细,涉及到其他系统,还是得找到对方接口的开发,很重要,至少能节约半天以上时间。

你可能感兴趣的:(C#,webservice,webservice)