如何向 VB.NET 2008 SOAP 请求添加标头?

Posted

技术标签:

【中文标题】如何向 VB.NET 2008 SOAP 请求添加标头?【英文标题】:How do I add a header to a VB.NET 2008 SOAP request? 【发布时间】:2012-10-12 11:21:07 【问题描述】:

我有一个 VB.NET 2008 程序,它可以访问由 WSDL 定义并使用 SOAP 协议的 Siebel Web 服务。

Siebel Web 服务要求在服务请求中包含一个包含用户名、密码和会话类型的标头,但该标头未在 WSDL 中定义。

因此,当我使用 soapUI 实用程序测试 WSDL 时,WSDL 定义的请求如下所示:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:lov="http://www.siebel.com/xml/LOVService" xmlns:lis="http://www.siebel.com/xml/ListQuery">
<soapenv:Header/>
   <soapenv:Body>
      <lov:EAILOVGetListOfValues_Input>
         <lis:ListsQuery>
            <lis:ListQuery>
               <lis:Active>Y</lis:Active>
               <lis:LanguageCode>ENU</lis:LanguageCode>
               <lis:Type>CUT_ACCOUNT_TYPE</lis:Type>
            </lis:ListQuery>
         </lis:ListsQuery>
      </lov:EAILOVGetListOfValues_Input>
   </soapenv:Body>
</soapenv:Envelope>

但上述内容不起作用,因为它包含一个缺少用户和会话凭据的空标头。只有当我手动将&lt;soapenv:Header/&gt; 替换为包含用户名、密码和会话类型的标头时,它才有效,如下所示:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:lov="http://www.siebel.com/xml/LOVService" xmlns:lis="http://www.siebel.com/xml/ListQuery">
<soapenv:Header>
  <UsernameToken xmlns="http://siebel.com/webservices">TESTUSER</UsernameToken>
  <PasswordText xmlns="http://siebel.com/webservices">TESTPASSWORD</PasswordText>
  <SessionType xmlns="http://siebel.com/webservices">None</SessionType>
</soapenv:Header>
   <soapenv:Body>
      <lov:EAILOVGetListOfValues_Input>
         <lis:ListsQuery>
            <lis:ListQuery>
               <lis:Active>Y</lis:Active>
               <lis:LanguageCode>ENU</lis:LanguageCode>
               <lis:Type>CUT_ACCOUNT_TYPE</lis:Type>
            </lis:ListQuery>
         </lis:ListsQuery>
      </lov:EAILOVGetListOfValues_Input>
   </soapenv:Body>
</soapenv:Envelope>

我的问题是我无法弄清楚如何将以上内容翻译成 VB.NET 2008 代码。

将 WSDL 导入 Visual Studio 2008、在 VB 代码中定义服务并引用 Web 服务方法时,我没有问题。但是,我无法理清如何在 VB 中定义 Web 服务,以便更新的标头包含在 Web 服务请求中,而不是空标头。因此,我从 VB 发出的所有服务请求都失败了。

我可以定义一个继承自 SoapHeader 类的类...

Public Class MySoapHeader : Inherits System.Web.Services.Protocols.SoapHeader
    Public Username As String
    Public Password As String
    Public SessionType As String
End Class

...但是如何在 VB 发出的 SOAP 请求中包含此标头?

我用来测试的示例代码是一个带有按钮和列表框的简单表单。

Public Class Form1

    Private Sub btnGetLOV_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGetLOV.Click

        Dim MyService As New wsLOV.EAILOVPortClient

        Dim MyInput As New wsLOV.EAILOVGetListOfValues_Input
        Dim MyParams(0) As wsLOV.ListQuery
        Dim temp As New wsLOV.ListQuery

        Dim MyResult As New wsLOV.EAILOVGetListOfValues_Output

        temp.Active = "Y"
        temp.Type = "CUT_ACCOUNT_TYPE"
        temp.LanguageCode = "ENU"
        MyParams(0) = temp

        MyInput.ListsQuery = MyParams

        Dim MyRequest As New wsLOV.EAILOVGetListOfValuesRequest(MyInput)
        MyResult = MyService.EAILOVGetListOfValues(MyInput)


    End Sub

End Class

代码在子例程的最后一行失败,并显示一条消息,指示请求尚未通过身份验证(错误代码:10944642 错误消息:错误:入站 SOAP 消息 - 会话令牌丢失或无效或已过期),即当我离开包含用户名、密码和会话类型的标头时,我在soapUI 中遇到同样的错误。

我认为我需要将标头添加到端点(每个 http://msdn.microsoft.com/en-us/library/ms731749.aspx 和 http://msdn.microsoft.com/en-us/library/system.servicemodel.configuration.serviceendpointelement.aspx),但我不确定如何在 VB 中执行此操作。

【问题讨论】:

服务的 WSDL 损坏,服务提供者需要修复 WSDL。 它没有坏。 WSDL 由 Siebel 自动生成。 这并不意味着它没有或不能被破坏。 关键问题是您的客户端代理是什么,是新服务客户端还是老式网络参考? 刚刚编辑了帖子以包含有关我正在使用的测试客户端的其他信息。 wsLOV 名称是由 WSDL 文件定义的服务引用(使用 VS2008 的“添加服务引用”对话框。 【参考方案1】:

以下是我们解决此问题的方法。关键似乎是使用附加标头实例化端点,而不是在端点已经实例化后尝试添加标头。

Imports System.ServiceModel.Channels
Imports System.ServiceModel

Public Class Form1

    Private Sub btnGetOrg_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGetOrgType.Click
        ' This example code queries the Siebel web service using the SOAP protocol for a list of
        ' Account (organization) types stored in a List of Values (LOV). The service request
        ' requires that a SOAP header be added that contains the username, password, and session
        ' type. We have to add this header because the WSDL file definition generated by Siebel
        ' does not include the header definition. The WSDL file was added to the VS2008 project as
        ' a Service Reference named "wsGetLOV"

        ' Create address headers for special services and add them to an array
        Dim addressHeader1 As AddressHeader = AddressHeader.CreateAddressHeader("UsernameToken", "http://siebel.com/webservices", "TESTUSER")
        Dim addressHeader2 As AddressHeader = AddressHeader.CreateAddressHeader("PasswordText", "http://siebel.com/webservices", "TESTPASSWORD")
        Dim addressHeader3 As AddressHeader = AddressHeader.CreateAddressHeader("SessionType", "http://siebel.com/webservices", "None")
        Dim addressHeaders() As AddressHeader = addressHeader1, addressHeader2, addressHeader3

        ' Endpoint address constructor with URI and address headers
        ' Replace <servername> in the following line with the name of your Siebel server.
        ' For example: http://actual-server/eai_enu...
        Dim endpointAddressWithHeaders As New EndpointAddress(New Uri("http://<servername>/eai_enu/start.swe?SWEExtSource=WebService&SWEExtCmd=Execute&WSSOAP=1"), addressHeaders)
        Dim MyService As New wsGetLOV.EAILOVPortClient("EAILOVPort", endpointAddressWithHeaders)

        Dim MyInput As New wsGetLOV.EAILOVGetListOfValues_Input
        Dim MyOutput As wsGetLOV.EAILOVGetListOfValues_Output
        Dim MyList(0) As wsGetLOV.ListQuery

        MyList(0) = New wsGetLOV.ListQuery
        MyList(0).Active = "Y"
        MyList(0).LanguageCode = "ENU"
        MyList(0).Type = "CUT_ACCOUNT_TYPE"
        MyInput.ListsQuery = MyList

        MyOutput = MyService.EAILOVGetListOfValues(MyInput)

        Dim myStrings As New List(Of String)

        ' We use nested loops because the results returned by the service is a list of
        ' lists though in our case, the result set is a list with a single item (this item
        ' being a list of multiple items)
        For Each myResultList As wsGetLOV.ListResult In MyOutput.ListsResult
            For Each myResultValue As wsGetLOV.ListValueResult In myResultList.ListValuesResult
                myStrings.Add(myResultValue.Value)
            Next
        Next

        ListBox1.DataSource = myStrings

    End Sub
End Class

【讨论】:

以上是关于如何向 VB.NET 2008 SOAP 请求添加标头?的主要内容,如果未能解决你的问题,请参考以下文章

VB.NET 2008 怎么给软件打包?能不能做成一个exe文件?

从 .NET 向 Access (Jet) 表添加列

向 SQL Server VB.NET 数据库添加多个值

如何向 SOAP XML 添加新元素

向 VB.Net 应用程序添加命令行参数

如何使用 Savon 向 SOAP 标头添加属性?