码迷,mamicode.com
首页 > 编程语言 > 详细

Python之Suds库调用WCF实现复杂参数序列化

时间:2018-02-10 17:00:05      阅读:412      评论:0      收藏:0      [点我收藏+]

标签:更改   .config   spn   接口自动化   属性   信息   工作   art   访问权限   

今年主要做自动化测技术支持工作,最近一直在做接口自动化这块,前些天在研究将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; }
    }

}
View Code
技术分享图片
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;
        }

    }
}
View Code

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>
View Code

3.启动服务

技术分享图片
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(WcfServiceDemo.ServiceDemo)))
            {
                host.Open();
                Console.WriteLine("服务已开启");
                Console.Read();
            }
        }
View Code

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(123)
    print result
View Code
技术分享图片
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
View Code

技术分享图片

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
View Code

具体实现

技术分享图片
# -*- 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(123)
    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=01
    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
View Code

三、遇到的问题

在上面配置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‘.")

 

Python之Suds库调用WCF实现复杂参数序列化

标签:更改   .config   spn   接口自动化   属性   信息   工作   art   访问权限   

原文地址:https://www.cnblogs.com/5ishare/p/8439020.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!