对于我的程序,服务器要求的Header是这样(只是要添加两个简单的元素):
BigLuo
111
但Delphi中的SOAPHeader只能通过继承TSOAPHeader来实现,但这样就会把派生类的名字添加上去,变成了这样:
4
2005-01-06T15:01:26.531Z
怎么办?
4
2005-01-06T15:01:26.531Z
实现方法是:
1.先定义一个TSOAPHeader的继承类,要在SOAP包中出现的字段以property方式出现
2.在initialization中注册
3.使用:
2. 我的要求和问题
对于我的程序,服务器要求的Header是这样
BigLuo
111
与上面的不同是Header下直接是两个元素,没有一个NS1:AuthHeader的外包层
仔细查看了一下Delphi的帮助,在Defining and using SOAP headers一节淘到如下一段
从最后一句看,我只要这样定义:
然后按如下方式注册
(Password一项也类似处理)
应该就可以了。
但运行一下发现文档里面说的根本就不对,而是这样:
y19451
mypass
看样子xoSimpleTypeWrapper根本没有任何作用(不加那一句也是这个结果)
在帮助文件里面来回折腾了半天,看到RegisterSerializeOptions的帮助里提到这样一个选项
这个选项倒好像跟我的需求比较接近哦,试试!
结果又是失望。“希望,失望,希望,失望”,麦兜抱怨到。
在google上搜索了半天没有发现什么有用的结果,在无望之余回来又来看Delphi提供的例子,注意到它的例子中将AuthHeader这个类注册了一下:
总结一下:
帮助里面说的应该是纯常量作为Header的情况,对于我这种... ... 的情况,应该按如下方式处理:
1. 按上面所说,声明HdrUsername和HdrPassword
2. 在initialization时按如下方式注册
其实这样也可以(而且简单一点):
1. 将Username和Password声明在一个Header内
以下内容为程序代码:
2.将TMsgHdr注册:
总的来说,还是看E文水平不够啊
a. 如果只对HdrUsername加xoSimpleTypeWrapper选项:
y19451Password
可以注意到Username元素不见了,只能见到其值y19451赤裸地出现,而Password一项正常
b.如果只对HdrPassword加xoSimpleTypeWrapper选项:
运行时会出现"Element does not contain a single text node"这样的错误。我估计SOAP Header如下,Password的出现导致了这不是一个合法的XML
y19451 Password
c.如果两者都加xoSimpleTypeWrapper选项,结果会是怎样呢?
Password
居然Username都不见了
但Delphi中的SOAPHeader只能通过继承TSOAPHeader来实现,但这样就会把派生类的名字添加上去,变成了这样:
1.Delphi给了一个SOAP Header的示例
实现方法是:
1.先定义一个TSOAPHeader的继承类,要在SOAP包中出现的字段以property方式出现
AuthHeader = class(TSOAPHeader)
private
FAccNumber: Integer;
FTimeStamp: TXSDateTime;
public
destructor Destroy; override; //用于释放FTimeStamp,别无它用
published
property AccNumber: Integer read FAccNumber write FAccNumber;
property TimeStamp: TXSDateTime read FTimeStamp write FTimeStamp;
end;
private
FAccNumber: Integer;
FTimeStamp: TXSDateTime;
public
destructor Destroy; override; //用于释放FTimeStamp,别无它用
published
property AccNumber: Integer read FAccNumber write FAccNumber;
property TimeStamp: TXSDateTime read FTimeStamp write FTimeStamp;
end;
2.在initialization中注册
InvRegistry.RegisterHeaderClass(TypeInfo(IBankAccount), AuthHeader, 'AuthHeader', 'urn:BankAccountIntf');
RemClassRegistry.RegisterXSClass(AuthHeader, 'urn:BankAccountIntf', 'AuthHeader');
RemClassRegistry.RegisterXSClass(AuthHeader, 'urn:BankAccountIntf', 'AuthHeader');
3.使用:
var
H: AuthHeader;
svc: IBankAccount;
begin
svc := HTTPRIO1 as IBankAccount;
H := AuthHeader.Create;
try
H.AccNumber := FAuthKey;
H.TimeStamp := DateTimeToXSDateTime(FTimeStamp, True);
if UseHeader then
(svc as ISOAPHeaders).send(H);
svc.some_method(...)
finally
H.Free;
end
H: AuthHeader;
svc: IBankAccount;
begin
svc := HTTPRIO1 as IBankAccount;
H := AuthHeader.Create;
try
H.AccNumber := FAuthKey;
H.TimeStamp := DateTimeToXSDateTime(FTimeStamp, True);
if UseHeader then
(svc as ISOAPHeaders).send(H);
svc.some_method(...)
finally
H.Free;
end
2. 我的要求和问题
对于我的程序,服务器要求的Header是这样
与上面的不同是Header下直接是两个元素,没有一个NS1:AuthHeader的外包层
仔细查看了一下Delphi的帮助,在Defining and using SOAP headers一节淘到如下一段
Handling scalar-type headers
Some Web Services define and use headers that are simple types (such as an integer or string) rather than a complex structure that corresponds to a remotable type. However, Delphi's support for SOAP headers requires that you use a TSOAPHeader descendant to represent header types. You can define header classes for simple types by treating the TSOAPHeader class as a holder class. That is, the TSOAPHeader descendant has a single published property, which is the type of the actual header. To signal that the SOAP representation does not need to include a node for the TSOAPHeader descendant, call the remotable type registry's RegisterSerializeOptions method (after registering the header type) and give your header type an option of xoSimpleTypeWrapper.
Some Web Services define and use headers that are simple types (such as an integer or string) rather than a complex structure that corresponds to a remotable type. However, Delphi's support for SOAP headers requires that you use a TSOAPHeader descendant to represent header types. You can define header classes for simple types by treating the TSOAPHeader class as a holder class. That is, the TSOAPHeader descendant has a single published property, which is the type of the actual header. To signal that the SOAP representation does not need to include a node for the TSOAPHeader descendant, call the remotable type registry's RegisterSerializeOptions method (after registering the header type) and give your header type an option of xoSimpleTypeWrapper.
从最后一句看,我只要这样定义:
HdrUsername = class(TSOAPHeader)
private
FUsername: String;
published
property Username: String read FUsername write FUsername;
end;
private
FUsername: String;
published
property Username: String read FUsername write FUsername;
end;
然后按如下方式注册
InvRegistry.RegisterHeaderClass(TypeInfo(ezMsgServer), HdrUsername, 'Username', ');
RemClassRegistry.RegisterSerializeOptions(TypeInfo(HdrUsername), [xoSimpleTypeWrapper]);
RemClassRegistry.RegisterSerializeOptions(TypeInfo(HdrUsername), [xoSimpleTypeWrapper]);
(Password一项也类似处理)
应该就可以了。
但运行一下发现文档里面说的根本就不对,而是这样:
看样子xoSimpleTypeWrapper根本没有任何作用(不加那一句也是这个结果)
3. 问题的解决
在帮助文件里面来回折腾了半天,看到RegisterSerializeOptions的帮助里提到这样一个选项
xoHolderClass
The remotable object corresponds to a "holder" class. That is, the SOAP representation does not include a node for the class itself, just for its members. This is used when a type that would otherwise not require a remotable class uses a feature only available on remotable classes (such as attributes).
The remotable object corresponds to a "holder" class. That is, the SOAP representation does not include a node for the class itself, just for its members. This is used when a type that would otherwise not require a remotable class uses a feature only available on remotable classes (such as attributes).
这个选项倒好像跟我的需求比较接近哦,试试!
结果又是失望。“希望,失望,希望,失望”,麦兜抱怨到。
在google上搜索了半天没有发现什么有用的结果,在无望之余回来又来看Delphi提供的例子,注意到它的例子中将AuthHeader这个类注册了一下:
RemClassRegistry.RegisterXSClass(AuthHeader, 'urn:BankAccountIntf', 'AuthHeader');
对啊,这个类应该在Remote Class Registry里面注册,于是加上HdrUsername和HdrPassword的注册语句, 再试,搞定!总结一下:
帮助里面说的应该是纯常量作为Header的情况,对于我这种
1. 按上面所说,声明HdrUsername和HdrPassword
2. 在initialization时按如下方式注册
InvRegistry.RegisterHeaderClass(TypeInfo(ezMsgServer), HdrUsername, 'Username', ');
RemClassRegistry.RegisterXSClass(HdrUsername, ', 'Username', 'Username');
RemClassRegistry.RegisterSerializeOptions(TypeInfo(HdrUsername), [xoHolderClass]);
InvRegistry.RegisterHeaderClass(TypeInfo(ezMsgServer), HdrPassword, 'Password', ');
RemClassRegistry.RegisterXSClass(HdrPassword, ', 'Password', 'Password');
RemClassRegistry.RegisterSerializeOptions(HdrPassword, [xoHolderClass]);
RemClassRegistry.RegisterXSClass(HdrUsername, ', 'Username', 'Username');
RemClassRegistry.RegisterSerializeOptions(TypeInfo(HdrUsername), [xoHolderClass]);
InvRegistry.RegisterHeaderClass(TypeInfo(ezMsgServer), HdrPassword, 'Password', ');
RemClassRegistry.RegisterXSClass(HdrPassword, ', 'Password', 'Password');
RemClassRegistry.RegisterSerializeOptions(HdrPassword, [xoHolderClass]);
其实这样也可以(而且简单一点):
1. 将Username和Password声明在一个Header内
以下内容为程序代码:
TezMsgHdr = class(TSOAPHeader)
private
FUsername: String;
FPassword: String;
published
property Username: String read FUsername write FUsername;
property Password: String read FPassword write FPassword;
end;
private
FUsername: String;
FPassword: String;
published
property Username: String read FUsername write FUsername;
property Password: String read FPassword write FPassword;
end;
2.将TMsgHdr注册:
InvRegistry.RegisterHeaderClass(TypeInfo(ezMsgServer), TezMsgHdr, 'Username', ', hmtRequest);
RemClassRegistry.RegisterXSInfo(TypeInfo(TezMsgHdr), ', 'Username', 'Username');
RemClassRegistry.RegisterSerializeOptions(TypeInfo(TezMsgHdr), [xoSimpleTypeWrapper, xoHolderClass]);
RemClassRegistry.RegisterXSInfo(TypeInfo(TezMsgHdr), ', 'Username', 'Username');
RemClassRegistry.RegisterSerializeOptions(TypeInfo(TezMsgHdr), [xoSimpleTypeWrapper, xoHolderClass]);
总的来说,还是看E文水平不够啊
4. 其他
细心的话,可以注意到后面一种方法里面多了一个xoSimpleTypeWrapper选项。其实对于后一种方法的复杂类TezMsgHdr, 这个选项是无效的,但对于前一种,就有些不同了(正如其名称所表明的那样,只有真正是SimpleType才有作用):a. 如果只对HdrUsername加xoSimpleTypeWrapper选项:
可以注意到Username元素不见了,只能见到其值y19451赤裸地出现,而Password一项正常
b.如果只对HdrPassword加xoSimpleTypeWrapper选项:
运行时会出现"Element does not contain a single text node"这样的错误。我估计SOAP Header如下,Password的出现导致了这不是一个合法的XML
c.如果两者都加xoSimpleTypeWrapper选项,结果会是怎样呢?
居然Username都不见了
没有评论:
发表评论