今年主要做自动化测试技术支持工作,最近一直在做接口自动化这块,前些天在研究将web页面模拟http进行接口自动化,这周杭州那边想测试WCF服务,所以这两天一直在探索。遇到的第一个问题就是服务参数传参序列化的问题,怎么让python这边创建的对象能被WCF识别到。正好在大学的时候也学了WCF,不过一直都没用过,这次算是重温一下,用的都是一些WCF基础。

一、WCF服务准备

1.定义契约Contract

这里IServiceDemo.cs定义了服务契约IServiceDemo,并定义了几个操作契约OperationContract,5个操作契约传的参数不同,用来做测试,同时自定义了两个数据契约DataContract.并在ServiceDemo.svc中实现了上面操作契约。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text; namespace WcfServiceDemo
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。
[ServiceContract]
public interface IServiceDemo
{ [OperationContract]
string GetSimpleData(string value); [OperationContract]
List<Item> GetListData(List<Item> items); [OperationContract]
Item GetModelData(Item item); [OperationContract]
Dictionary<string,string> GetDicData(Dictionary<string,string> dic); [OperationContract]
Dictionary<string, Dictionary<string,int>[]> GetDicDicData(Dictionary<string, Dictionary<string, int>[]> dic); }
[DataContract]
public class ItemMenu
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Value { get; set; }
}
[DataContract]
public class Item
{
[DataMember]
public List<ItemMenu> ItemMenus { get; set; }
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text; namespace WcfServiceDemo
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
// 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 Service1.svc 或 Service1.svc.cs,然后开始调试。
public class ServiceDemo : IServiceDemo
{ public string GetSimpleData(string value)
{
return value;
}
public List<Item> GetListData(List<Item> items)
{
return items;
}
public Item GetModelData(Item item)
{
return item;
}
public Dictionary<string, string> GetDicData(Dictionary<string, string> dic)
{
return dic;
}
public Dictionary<string, Dictionary<string, int>[]> GetDicDicData(Dictionary<string, Dictionary<string, int>[]> dic)
{
return dic;
} }
}

2.定义宿主

WCF宿主可以有多种方式,这里用了控制台应用程序来作为宿主,主要是想着做demo,可以发给测试,用控制台不用像iis那样部署了。在控制台应用程序的App.config中配置wcf服务。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="WcfServiceDemo.ServiceDemo" behaviorConfiguration="ServiceDemoBehavior" >
<endpoint address="" contract="WcfServiceDemo.IServiceDemo" binding="basicHttpBinding"></endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8001/ServiceDemo/"></add>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceDemoBehavior">
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>

3.启动服务

        static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(WcfServiceDemo.ServiceDemo)))
{
host.Open();
Console.WriteLine("服务已开启");
Console.Read();
}
}

4.出现的问题

在启动服务的时候,报了:HTTP 无法注册 URL http://+:8001/ServiceDemo/。进程不具有此命名空间的访问权限的错误。解决方法是VS2015用管理员打开就好了。

二.suds.client的使用

1.了解WCF

要调用WCF,首先得知道服务中有哪些参数,每个参数具体是什么类型。可以使用sud.client实例化client,然后打印出来看服务里面的内容。

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8') from suds.client import Client if __name__ == '__main__': client=Client('http://localhost:8001/ServiceDemo/?singleWsdl')
print client
# -----------------简单类型---------------------------
result= client.service.GetSimpleData('')
print result
Service ( ServiceDemo ) tns="http://tempuri.org/"
Prefixes (4)
ns0 = "http://schemas.datacontract.org/2004/07/WcfServiceDemo"
ns1 = "http://schemas.microsoft.com/2003/10/Serialization/"
ns2 = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"
ns3 = "http://tempuri.org/"
Ports (1):
(BasicHttpBinding_IServiceDemo)
Methods (5):
GetDicData(ns2:ArrayOfKeyValueOfstringstring dic, )
GetDicDicData(ns2:ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1 dic, )
GetListData(ns0:ArrayOfItem items, )
GetModelData(ns0:Item item, )
GetSimpleData(xs:string value, )
Types (11):
ns2:ArrayOfArrayOfKeyValueOfstringint
ns0:ArrayOfItem
ns0:ArrayOfItemMenu
ns2:ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1
ns2:ArrayOfKeyValueOfstringint
ns2:ArrayOfKeyValueOfstringstring
ns0:Item
ns0:ItemMenu
ns1:char
ns1:duration
ns1:guid

2.参数序列化

对于基础类型的参数可以直接传参,但复杂类型参数就比较麻烦了,怎么样在python定义的参数能在wcf服务端识别出来,也就是序列化反序列化的问题,例如GetDicDicData方法中要传递ns2:ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1类型的参数,在python中怎么定义呢,这个类型里面包含哪些属性,怎么实例化这个参数,可以使用client.factory.create('参数类型名')来创建,有时类型下面还有子类,所以在传参数时要弄清楚对象里面子类的数据类型,从根到叶子,而在实例化参数时需要从叶子到根来组装成对象。还有获取结果后获取解析的问题,这个把结果打印出来后可以一层一层的获取值。也可以调用last_received()方法,返回的是xml,然后用xpath解析。

    print client.factory.create('ns2:ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1')
print client.factory.create('ns2:KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1')
print client.factory.create('ns2:ArrayOfArrayOfKeyValueOfstringint')
print client.factory.create('ns2:ArrayOfKeyValueOfstringint')
print client.factory.create('ns2:KeyValueOfstringint')
KeyValueOfstringint=client.factory.create('ns2:KeyValueOfstringint')
KeyValueOfstringint.Key='cyw'
KeyValueOfstringint.Value = 1
ArrayOfKeyValueOfstringint=client.factory.create('ns2:ArrayOfKeyValueOfstringint')
ArrayOfKeyValueOfstringint.KeyValueOfstringint=[KeyValueOfstringint]
ArrayOfArrayOfKeyValueOfstringint=client.factory.create('ns2:ArrayOfArrayOfKeyValueOfstringint')
ArrayOfArrayOfKeyValueOfstringint.ArrayOfKeyValueOfstringint=[ArrayOfKeyValueOfstringint]
KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1 = client.factory.create('ns2:KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1')
KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1.Key = 'cuiyw'
KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1.Value = ArrayOfArrayOfKeyValueOfstringint
ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1 = client.factory.create('ns2:ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1')
ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1.KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1 = KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1

具体实现

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8') from suds.client import Client if __name__ == '__main__': client=Client('http://localhost:8001/ServiceDemo/?singleWsdl')
print client
# -----------------简单类型---------------------------
result= client.service.GetSimpleData('')
print result # -----------------自定义类---------------------------
print client.factory.create('ns0:Item')
print client.factory.create('ns0:ArrayOfItemMenu')
print client.factory.create('ns0:ItemMenu')
ItemMenu=client.factory.create('ns0:ItemMenu')
ItemMenu.Name='Cyw'
ItemMenu.Value = 'Cuiyw'
ArrayOfItemMenu= client.factory.create('ns0:ArrayOfItemMenu')
ArrayOfItemMenu.ItemMenu=[ItemMenu,ItemMenu]
Item=client.factory.create('ns0:Item')
Item.ItemMenus=ArrayOfItemMenu
result= client.service.GetModelData(Item)
print result
print result.ItemMenus.ItemMenu[0].Name
print result.ItemMenus.ItemMenu[0].Value # -----------------自定义类列表---------------------------
print client.factory.create('ns0:ArrayOfItem')
ArrayOfItem =client.factory.create('ns0:ArrayOfItem')
ArrayOfItem.Item=[Item,Item]
result= client.service.GetListData(ArrayOfItem)
print result
print result.Item[0].ItemMenus.ItemMenu[0].Name
# -----------------字典类型---------------------------
print client.factory.create('ns2:ArrayOfKeyValueOfstringstring')
print client.factory.create('ns2:KeyValueOfstringstring')
KeyValueOfstringstring= client.factory.create('ns2:KeyValueOfstringstring')
KeyValueOfstringstring.Key=''
KeyValueOfstringstring.Value = 'cyw'
ArrayOfKeyValueOfstringstring=client.factory.create('ns2:ArrayOfKeyValueOfstringstring')
ArrayOfKeyValueOfstringstring.KeyValueOfstringstring=[KeyValueOfstringstring]
result= client.service.GetDicData(ArrayOfKeyValueOfstringstring)
print result.KeyValueOfstringstring[0].Key
print result.KeyValueOfstringstring[0].Value
# print client.last_received() # -----------------字典嵌套---------------------------
print client.factory.create('ns2:ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1')
print client.factory.create('ns2:KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1')
print client.factory.create('ns2:ArrayOfArrayOfKeyValueOfstringint')
print client.factory.create('ns2:ArrayOfKeyValueOfstringint')
print client.factory.create('ns2:KeyValueOfstringint')
KeyValueOfstringint=client.factory.create('ns2:KeyValueOfstringint')
KeyValueOfstringint.Key='cyw'
KeyValueOfstringint.Value = 1
ArrayOfKeyValueOfstringint=client.factory.create('ns2:ArrayOfKeyValueOfstringint')
ArrayOfKeyValueOfstringint.KeyValueOfstringint=[KeyValueOfstringint]
ArrayOfArrayOfKeyValueOfstringint=client.factory.create('ns2:ArrayOfArrayOfKeyValueOfstringint')
ArrayOfArrayOfKeyValueOfstringint.ArrayOfKeyValueOfstringint=[ArrayOfKeyValueOfstringint]
KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1 = client.factory.create('ns2:KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1')
KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1.Key = 'cuiyw'
KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1.Value = ArrayOfArrayOfKeyValueOfstringint
ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1 = client.factory.create('ns2:ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1')
ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1.KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1 = KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1
result= client.service.GetDicDicData(ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1)
print result.KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1[0].Key
print result.KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1[0].Value

三、遇到的问题

在上面配置WCF服务时我把终结点配置的绑定配置成wsHttpBinding,导致在python调用时出现下面的错误。当启动新实例启动服务时是可以的,但使用宿主就不行,昨天没找到解决方法,今天把昨天写的在自己电脑上重现了下还是出现这个问题,找了半天没想到还真解决了。

<endpoint address="" contract="WcfServiceDemo.IServiceDemo" binding="wsHttpBinding"></endpoint>
Exception: (415, u"Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'.")

四、zeep client库的使用

昨天查Suds不支持wsHttpBinding,今天就尝试用zeep库来尝试。

1、WCF服务配置

首先是配置wsHttpBinding,使用zeep时需要wsHttpBinding配置<security mode="None">。其他与上一博客使用Suds序列化反序列化一样。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IWCFService" >
<security mode="None">
</security>
</binding>
</wsHttpBinding> </bindings>
<services>
<service name="WcfServiceDemo.ServiceDemo" behaviorConfiguration="ServiceDemoBehavior" >
<endpoint address="" contract="WcfServiceDemo.IServiceDemo" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IWCFService"></endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8001/ServiceDemo/"></add>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceDemoBehavior">
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>

2、zeep client的使用

参数序列化反序列化,这里传入参数和返回值一样,就是为了验证传入参数正确与否。

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
from zeep import Client if __name__ == '__main__':
client = Client('http://localhost:8021/ServiceDemo/?singleWsdl')
print client
print client.namespaces
#-------------------基础数据类型---------------
print client.service.GetSimpleData('abc')
# -------------------自定义Model类型---------------
ItemMenuType = client.get_type('ns2:ItemMenu')
itemMenu= ItemMenuType(Name='cyw',Value='abc')
ArrayOfItemMenuType = client.get_type('ns2:ArrayOfItemMenu')
print ArrayOfItemMenuType
itemMenus=ArrayOfItemMenuType(ItemMenu=[itemMenu,itemMenu])
print itemMenus
ItemType= client.get_type('ns2:Item')
print ItemType
item=ItemType(ItemMenus=itemMenus)
print item
print client.service.GetModelData(item)
# -------------------自定义Model List类型---------------
ArrayOfItem = client.get_type('ns2:ArrayOfItem')
items= ArrayOfItem(Item=[item,item])
print client.service.GetListData(items)
# -------------------字典类型---------------
ArrayOfKeyValueOfstringstringType = client.get_type('ns3:ArrayOfKeyValueOfstringstring')
print ArrayOfKeyValueOfstringstringType
dic=ArrayOfKeyValueOfstringstringType(KeyValueOfstringstring=[{'Key':'a','Value':'aaa'},{'Key':'b','Value':'bbb'}])
print dic
# -------------------字典嵌套类型---------------
ArrayOfKeyValueOfstringintType = client.get_type('ns3:ArrayOfKeyValueOfstringint')
print ArrayOfKeyValueOfstringintType
dic=ArrayOfKeyValueOfstringintType(KeyValueOfstringint=[{'Key':'a','Value':1},{'Key':'b','Value':2}])
print dic
ArrayOfArrayOfKeyValueOfstringintType = client.get_type('ns3:ArrayOfArrayOfKeyValueOfstringint')
arrdic= ArrayOfArrayOfKeyValueOfstringintType(ArrayOfKeyValueOfstringint=[dic])
ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1Type = client.get_type('ns3:ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1')
dicdic= ArrayOfKeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1Type(KeyValueOfstringArrayOfArrayOfKeyValueOfstringintty7Ep6D1={'Key':'c','Value':arrdic})
result= client.service.GetDicDicData(dicdic)
print result
print result[0].Value.ArrayOfKeyValueOfstringint[0].KeyValueOfstringint[0].Key

一直没找到怎么打印出wsdl的详细信息,今天算是找到了.

print client.wsdl.dump()

Python之Suds库调用WCF实现复杂参数序列化的更多相关文章

  1. Python之Suds库调用WCF时复杂参数序列化

    今天主要做自动化测技术支持工作,最近一直在做接口自动化这块,前些天在研究将web页面模拟http进行接口自动化,这周杭州那边想测试WCF服务,所以这两天一直在探索.遇到的第一个问题就是服务参数传参序列 ...

  2. python使用suds来调用webservice

    对于python仅作为客户端调用webservice的情况,推荐使用suds库来完成,比起zsi,soapy之类,它可以说是相当轻量级,使用非常方便. 安装suds建议使用easy_insall来做. ...

  3. Python使用suds调用webservice报错解决方法:AttributeError: 'Document' object has no attribute 'set'

    使用python的suds包调用webservice服务接口,报错:AttributeError: 'Document' object has no attribute 'set' 调用服务接口代码: ...

  4. python 各种开源库

    测试开发 来源:https://www.jianshu.com/p/ea6f7fb69501 Web UI测试自动化 splinter - web UI测试工具,基于selnium封装. 链接 sel ...

  5. python使用suds调用webservice接口

    最近做接口对接,遇到了.net开发的webservice接口,因为python第一次与webservice对接,连问带查,最后使用suds库来实现了 1.安装suds mac: sudo pip in ...

  6. python使用SUDS调用webservice

    最近做接口对接,遇到了.net开发的webservice接口,因为python第一次与webservice对接,连问带查,最后使用suds库来实现了 1.安装suds mac: sudo pip in ...

  7. 通过实例简介python使用ctypes模块调用C语言动态库

    看介绍python语言时,说它是胶水语言,可以调用其他语言.通过使用ctypes模块就可以调用C语言的动态库.下面先放上官方文档和几个比较好的博文. 1.官方文档:http://python.net/ ...

  8. VBA/VB6/VBS/VB.NET/C#/Python/PowerShell都能调用的API封装库

    API函数很强大,但是声明的时候比较繁琐. 我开发的封装库,包括窗口.键盘.鼠标.消息等常用功能.用户不需要添加API函数的声明,就可以用到API的功能. 在VBA.VB6的引用对话框中引用API.t ...

  9. 【Win 10应用开发】手动调用WCF服务

    调用服务最简单的方法就是,直接在VS里面添加服务引用,输入服务的地址即可,无论是普通Web服务,还是WCF服务均可.VS会根据获取到的元数据,自动生成客户端代码. 如果服务的调用量很大,应用广泛,可以 ...

随机推荐

  1. [bzoj4411] [Usaco2016 Feb]Load balancing

    先离散化一下(也可以不用 枚举横坐标,用线段树维护两边纵坐标上的节点数. 每次在线段树上二分...(感觉似乎树状数组也行? #include<cstdio> #include<ios ...

  2. 北京师范大学校赛C

    https://www.nowcoder.com/acm/contest/submit/0dff89ad7b8444719df155d507f3e1dd?ACMContestId=3&tagI ...

  3. Oracle_事务

    Oracle_事务 -事物管理   create table account(        id number,        money number );     --实现转账操作 update ...

  4. c++---天梯赛---查验身份证

    ★题目: ★题目分析:本题要求输入一个数字n,随后n行输入n个身份证号码.之后进行进一步的判断把错误的身份证号码输出.如果全部正确输出All passed. ★思路方法: ①按题目要求输入. ②对前1 ...

  5. 记node前后端代码共用的一次坑

    项目背景 nodejs项目,webpack打包,用axios请求,Promise封装,nunjucks模板引擎: 之前已将nunjucks模板通过webpack打包策略,做成前后端共用: 目前需要将网 ...

  6. Windows7下远程操作虚拟机

    ⒈分别查看两台物理机的IP地址 ⒉查看虚拟机的IP地址 ⒊两台物理机和虚拟机必须都要处于同一网段,上图中我已经做过了修改(每个节点都要修改,修改见步骤6 ) ⒋打开VMware,编辑虚拟机设置(每个节 ...

  7. dedecms织梦首页如何调用文章列表?

    如果冯耀宗博客类似,首页调用文章列表,同时也有许多企业站需要调用文章列表,今天我与大家来分享一下dedecms织梦首页如何调用文章列表? {dede:arclist     row='16'  tit ...

  8. 云主机与vps虚拟主机的区别

    云计算时代,云主机其可扩展性.价格便宜.安全可靠的特性深受企业和开发者欢迎,但目前有些IDC企业,新瓶装旧酒,将虚拟主机.VPS进行包装推出所谓的云主机服务,为了帮助用户更好的辨别和挑选云主机,下文详 ...

  9. 用dedecms做网站时,空间服务器选择IIS还是apache???

    想做一个dedecms程序的网站,不知道要选择什么样的空间,windows还是linux的?多大的空间比较适合?求高人回答.   如果是基于Linux平台的话,那不必多说自然是Apache了,因为II ...

  10. 用Dedecms5.7的arclist标签调用文章内容

    arclist标签调用文章内容 首先大家都知道在Dedecms中,list标签是可以调用文章内容的,调用格式就不再此冗述了.从我个人来说,我非常不喜欢用list标签调用,有可能我会尽量使用arclis ...