You are browsing the archive for VBA应用.

WebService系列:问题处理(Troubleshooting)

二月 14, 2009 in Oracle 融合中间件

 

 

WebService系列讲解PLSQL Web Service + OC4J 开发过程中遇到很多的问题,本文将一些常见的问题进行整理,以备后续查阅

这些问题的解决方案不一定是唯一的解决方法,参考的过程中请根据实际情况进行比较的筛选

 

1,OC4J运行Web Service:Missing <wsse:Security> in SOAP Header

原因:SOAP头中没有包括安全验证的信息,需要为请求的消息提供SOAP头信息

解决方案:实现IHeaderHandler接口的类,并赋给Soapclient30的实例;如果使用OC4J测试界面,选择必须的选项,让它包括头信息

 

2,VBA代理程序报错:解析SOAP头失败

背景:已经实现了IHeaderHandler接口,并赋给了Soapclient30的实例,同时OC4J服务器端没有报出任何错误,但是VBA代理程序报错:解析SOAP头失败

我遇到的原因:IHeaderHandler接口的实现类中IHeaderHandler_ReadHeader和IHeaderHandler_WillWriteHeaders函数没有返回True

解决方案:修改IHeaderHandler_ReadHeader和IHeaderHandler_WillWriteHeaders方法的返回值为True

 

3,OC4J运行Web Service:返回自定义Table类型报OWS-04005错误

原因:由于在JDeveloper中发布Web Services的时候没有包括自定义类型的实现类

解决方案:重新发布,选择需要的Java Class文件

 

4,PLSQL:传入Table参数多出一行空行

问题描述:传入的Table类型参数,传到PL/SQL端后,由于序列化的缘故,它会自动在Table后面添加一行空的记录因此在进行PL/SQL处理的时候,需要将Count减1。
                  否则很有可能报出不能插入Null的错误,当然这样的错误很有可能也是程序中没有提供必要的值,需要进行仔细的检查

解决方案:PLSQL程序中将PLSQL 记录表变量的数量减1

 

5,OC4J运行Web Service:Policy requires nonce

错误信息如下:ERROR OWS-04005 An error occurred for port: xxxx: oracle.j2ee.ws.common.soap.fault.SOAP11FaultException: Policy requires nonce.

原因:添加安全验证信息的时候有一个选项没有去掉(Nonce Required in Token/标记中所需的现时)

解决方案:修改Web Services的安全验证设置后重新发布或者在OC4J上面修改选项

 

6,OC4J运行Web Service:The security token could not be authenticated or authorized

原因:提供的安全验证用户名或者密码不正确,这个错误信息不属于程序的错误

解决方案:提供正确的信息,如果无法解决请找OC4J管理员协助

 

以上是我在实际的开发过程中遇到的一些关键问题!!!

 

WebService系列:Office VBA调用已安全性认证的Web Service

二月 14, 2009 in Oracle 融合中间件

 

上一篇文章中已经描述了如何生成 Office VBA 客户端代理程序来调用 Web Service,但是如果Web Service已

添加了安全性认证的话,仅仅使用MS Office2003 WebServices Tools工具产生的代理程序还不足以完成调用。

 

本文描述如何扩展Microsoft提供的SOAP Toolit中的IHeaderHandler接口来格式化SOAP Headers,进而实现

调用Web Service时提供必要的安全认证信息,本文只描述最基本的基于用户名口令认证方式。

 

一、编写安全认证的SOAP头信息

 

WebService系列:为WebService添加安全性一文中,当调用一个已添加安全验证的Web Service时,需要提供必要的验证信息,

验证信息包含在SOAP Header部分,本文的目标就是在VBA代理程序调用Web Service时,添加如下的SOAP Header信息到Web Service的请求消息中

1
2
3
4
5
 
 
 
               aronehome
               aronehome

 

在前面的文章中已经说明了VBA代理类主要完成的任务,其中就是初始化一个Soapclient30的实例,

而Soapclient30提供了一个属性HeaderHandler来接收实现IHeaderHandler接口的实现类。

而HeaderHandler对象定义了SOAP头如何读取和写入,下面就描述如何编写实现IHeaderHandler接口的VBA类模块 UserTokenAuthHelper 来返回一个OC4J Web Service能够识别的SOAP头信息。

下面是实现的类模块代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Option Explicit
 
Implements IHeaderHandler
 
Private Const XmlnsSoap As String = "http://schemas.xmlsoap.org/soap/envelope/"
Private Const SecurityXmlnsWsse As String = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
Private Const SecurityXmlns As String = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
Private Const SecurityXmlnsEnv As String = "http://schemas.xmlsoap.org/soap/envelope/"
Private Const UsernameTokenXmlnsWsse As String = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
Private Const UsernameTokenXmlns As String = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
Private Const WssePasswordType As String = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"
 
Private myUsernameToken As String
Private myPassword As String
Private myMustUnderstand As Integer
 
Public Property Let UsernameToken(ByVal pUsernameToken As String)
    myUsernameToken = pUsernameToken
End Property
 
Public Property Get UsernameToken() As String
    UsernameToken = myUsernameToken
End Property
 
Public Property Let Password(ByVal pPassword As String)
    myPassword = pPassword
End Property
 
Public Property Get Password() As String
    Password = myPassword
End Property
 
Public Property Let MustUnderstand(ByVal pMustUnderstand As Integer)
    myMustUnderstand = pMustUnderstand
End Property
 
Public Property Get MustUnderstand() As Integer
    MustUnderstand = myMustUnderstand
End Property
 
Private Function IHeaderHandler_ReadHeader(ByVal par_Reader As MSOSOAPLib30.ISoapReader, ByVal par_HeaderNode As MSXML2.IXMLDOMNode, ByVal par_Object As Object) As Boolean
    IHeaderHandler_ReadHeader = True
End Function
 
Private Function IHeaderHandler_WillWriteHeaders() As Boolean
    IHeaderHandler_WillWriteHeaders = True
End Function
 
Private Sub IHeaderHandler_WriteHeaders(ByVal par_ISoapSerializer As MSOSOAPLib30.ISoapSerializer, ByVal par_Object As Object)
    Dim tempHeaderDoc As String
    tempHeaderDoc = ""
    tempHeaderDoc = tempHeaderDoc &amp; " " _
                    &amp; "" _
    tempHeaderDoc = tempHeaderDoc &amp; " " _
                    &amp; "" &amp; myUsernameToken &amp; "" _
                    &amp; "" &amp; myPassword &amp; ""
    tempHeaderDoc = tempHeaderDoc &amp; "" _
                    &amp; "" _
                    &amp; ""
    par_ISoapSerializer.WriteXml tempHeaderDoc   
End Sub

上面的UserTokenAuthHelper类实现了按照OC4J的要求将安全验证需要的SOAP Header信息添加到请求消息中的功能

 

二、添加UserTokenAuthHelper实现类到Web Services代理类

 

上面已经实现了UserTokenAuthHelper类来添加SOAP Header信息,用于进行安全验证。只要修改MS Office2003 WebServices Tools生成的Web Services代理类,

将SOAP头信息传给消息即可,在代理类Class_Initialize()方法的最后添加如下的代码:

1
2
3
4
5
6
7
'用户认证
Dim objCurAuthHelper As UserTokenAuthHelper
Set objCurAuthHelper = New UserTokenAuthHelper
objCurAuthHelper.UsernameToken = "aronehome"
objCurAuthHelper.Password = "aronehome"
objCurAuthHelper.MustUnderstand = 1
Set sc_UserListInfo.HeaderHandler = objCurAuthHelper

 

在任何一个代理类都是相同的代码,只要根据实际代理类替换红色部分的Soapclient30变量就可以了。

 

再次运行VBA程序进行调试,提供正确的用户和密码,程序能够成功运行。上面代码中的用户名和密码直接写为aronehome/aronehome,根据情况进行修改,

最后将其修改为让用户录入的方式来提供,当然如果你提供错误的用户名或者密码,那Web Services返回的错误应该是:The security token could not be authenticated or authorized.

 

 

VBA客户端代理程序下载:Download TEMPLFLD_R11i Version 1

 

 

WebService系列:Office VBA调用Web Service

二月 13, 2009 in Oracle 融合中间件

 

 

Microsoft Office软件作为办公软件系统,已成为人们日常工作的必备工具,而其中的Excel更是各类人员的得力工具,

本文介绍基于Office VBA生成Web Service的客户端代理程序,使VBA程序能够调用Web Service。

 

基于的系统配置如下:

  1. Window XP
  2. Office 2003
  3. MS Office2003 WebServices Tools
  4. SOAP Toolkit3.0
  5. OC4J 10.1.3.3.0

 

一、使用MS Office2003 WebServices Tools

 

MS Office2003 WebServices Tools工具是为了简化在VBA中编写Web Services代理程序代码而设计的一个辅助工具,

它根据Web Services的wsdl描述文件生成对应的代理类以及用户自定义的类型结构类。

 

在 Office 应用程序中,单击“Visual Basic 编辑器”的“工具”菜单中的“Web 服务引用”即可启动 Microsoft Office 2003 Web Services Toolkit。

该工具提供了可用于下列用途的界面:

  1. 发现 Web 服务
  2. 选择所需的服务
  3. 创建为引用这些服务的 Visual Basic for Applications (VBA) 项目充当 Web 服务代理的类。

 

27.office2003_ws_tookit

 

选择“Web服务URL(U)”,输入wsdl的URL地址,如

http://ORACLE:8888/aronehome/UserListInfoSoapHttpPort

点击搜索按钮,右边会显示出Web Services拥有的方法,点击“添加”按钮创建各种类。

根据wsdl的描述内容,它会创建几个类型的类文件:

类前缀 类类型 说明
clsof_Factory_ 对象工厂 如果有用户定义的类型结构则产生
clsws_ Web 服务代理 Web Service的代理类,任何时候都产生
struct_ 用户定义的类型结构 非基本类型,用户自定义的类型则会产生,如PL/SQL中用户定义的Type或者Table都会产生

 

如上面的UserListInfo Web Services会产生如下的3个VBA类模块:

  1. clsof_Factory_UserListInfo
  2. clsws_UserListInfo
  3. struct_AronehomeDemoWs2User:对应的是PL/SQL中声明的user_type自定义类型

 

 

二、服务代理类模块描述

 

Web服务代理类模块主要完成以下工作:

  1. 实例化类(Class_Initialize),按照wsdl要求的类型创建一个SoapClient30对象实例
  2. 通过实例化的SoapClient30对象调用方法(wsm_getUserList(),wsm_updateUserInfo(ByVal ar_pUserList As Variant))
  3. 结束调用(Class_Terminate),释放资源

 

下面是clsws_UserListInfo服务的代理类模块的代码片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
Private sc_UserListInfo As SoapClient30
Private Const c_WSDL_URL As String = "http://oracle:8888/aronehome/UserListInfoSoapHttpPort?wsdl"
Private Const c_SERVICE As String = "UserListInfo"
Private Const c_PORT As String = "UserListInfoSoapHttpPort"
Private Const c_SERVICE_NAMESPACE As String = "http://com/aronehome/demo/UserListInfo.wsdl"
 
Private Sub Class_Initialize()
    Dim str_WSML As String
    str_WSML = ""
    str_WSML = str_WSML &amp; ""
    str_WSML = str_WSML &amp; ""
    str_WSML = str_WSML &amp; ""
    str_WSML = str_WSML &amp; ""
    str_WSML = str_WSML &amp; ""
    str_WSML = str_WSML &amp; ""
    str_WSML = str_WSML &amp; ""
 
    Set sc_UserListInfo = New SoapClient30
 
    sc_UserListInfo.MSSoapInit2 c_WSDL_URL, str_WSML, c_SERVICE, c_PORT, c_SERVICE_NAMESPACE
    'Use the proxy server defined in Internet Explorer's LAN settings by
    'setting ProxyServer to 
    sc_UserListInfo.ConnectorProperty("ProxyServer") = ""
    'Autodetect proxy settings if Internet Explorer is set to autodetect
    'by setting EnableAutoProxy to True
    sc_UserListInfo.ConnectorProperty("EnableAutoProxy") = True
 
    Set sc_UserListInfo.ClientProperty("GCTMObjectFactory") = New clsof_Factory_UserListInfo
 
End Sub
 
Private Sub Class_Terminate()
 
    'Error Trap
    On Error GoTo Class_TerminateTrap
 
    Set sc_UserListInfo = Nothing
 
Exit Sub
 
Class_TerminateTrap:
    UserListInfoErrorHandler ("Class_Terminate")
End Sub
 
Private Sub UserListInfoErrorHandler(str_Function As String)
 
    'SOAP Error
    If sc_UserListInfo.FaultCode &lt;&gt; "" Then
        Err.Raise vbObjectError, str_Function, sc_UserListInfo.FaultString
    'Non SOAP Error
    Else
        Err.Raise Err.Number, str_Function, Err.Description
    End If
 
End Sub
 
Public Function wsm_getUserList() As Variant
    'Error Trap
    On Error GoTo wsm_getUserListTrap
 
    wsm_getUserList = sc_UserListInfo.getUserList()
 
Exit Function
wsm_getUserListTrap:
    UserListInfoErrorHandler "wsm_getUserList"
End Function
 
Public Sub wsm_updateUserInfo(ByVal ar_pUserList As Variant)
    'Error Trap
    On Error GoTo wsm_updateUserInfoTrap
 
    sc_UserListInfo.updateUserInfo ar_pUserList
 
Exit Sub
wsm_updateUserInfoTrap:
    UserListInfoErrorHandler "wsm_updateUserInfo"
End Sub

 

这样VBA程序或者VBA宏就可以调用服务代理类中的方法来调用Web Service了 

 

三、编写VBA宏代码调用代理类方法来调用Web Service

 

上面通过MS Office2003 WebServices Tools工具已经生成了调用Web Service的VBA代理类,下面编写VBA宏代码来调用它们

 

1,调用结果返回自定义复杂类型

上面的PL/SQL函数示例声明中看到,get_user_list函数返回一个基于自定义类型user_type的Table类型user_tbl,

对应的是通过MS Office2003 WebServices Tools工具可以生成的代理类clsws_UserListInfo中的wsm_getUserList()方法

下面是VBA宏代码调用的片段:

1
2
3
4
5
6
7
8
9
10
11
Dim clsUserListInfo As clsws_UserListInfo
Dim objCurUserListArray() As struct_AronehomeDemoWs2User
Dim objCurUser As struct_AronehomeDemoWs2User
 
Set clsUserListInfo = New clsws_UserListInfo
objCurUserListArray = clsUserListInfo.wsm_getUserList
 
For i = 0 To UBound(objCurUserListArray)
    Set objCurUser = objCurUserListArray(i)
    MsgBox objCurUser.username + "" + objCurUser.password
Next

 

2,提供复杂数据类型参数调用WebServices

 

上面的PL/SQL函数示例声明中看到,update_user_info函数返回一个基于自定义类型user_type的Table类型user_tbl,

对应的是通过MS Office2003 WebServices Tools工具可以生成的代理类clsws_UserListInfo中的wsm_getUserList()方法

下面是VBA宏代码调用的代码片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Dim lines As Integer
Dim clsUpdateUserInfo As clsws_UserListInfo
Dim objCurUserInfoArrary() As struct_AronehomeDemoWs2User
Dim objCurUserInfo As struct_AronehomeDemoWs2User
 
lines = 3
 
ReDim objCurUserInfoArrary(lines) As struct_AronehomeDemoWs2User
 
For i = 1 To 3
    Set objCurUserInfo = New struct_AronehomeDemoWs2User
    objCurUserInfo.userid = i
    objCurUserInfo.username = "a" + i
    objCurUserInfo.password = "b" + i
 
    Set objCurUserInfoArray(i) = objCurUserInfo
Next
 
Set clsUpdateUserInfo = New clsws_UserListInfo
clsUpdateUserInfo.wsm_updateUserInfo objCurUserInfoArray

 

注:上面传给Web Service的Table为objCurUserInfoArray,而PL/SQL在接收到这个Table时的count数要比实际的多一行,多出的一行全是空值,

是由于SOAP在进行序列化的过程中添加的,因此在PL/SQL代码中,需要将传入的Table变量的count数减去1,可能有的同学已经注意到PLSQL update_user_info方法中的“p_user_list.count -1”了。

 

三、执行VBA程序

 

如果上面的Web Service按照前期的课题中一样添加的安全性配置,那通过上面的代码在VBA程序中调用Web Services是执行不成功的,报出如下的错误:
ERROR OWS-04005: Missing <wsse:Security> in SOAP Header
和我们使用OC4J自带的测试页面进行测试时一样的错误,是由于没有提供安全验证信息到SOAP Header中。
而通过MS Office2003 WebServices Tools工具为我们产生的Web Services代理类中没有安全验证相关的内容,我们需要自己编写程序来产生SOAP Header的内容

 

 

下一篇文章将描述如何在VBA调用中添加认证信息以支持Web Service的认证