这是在EWS中调用ResolveNames的工作示例代码,该代码是我从Exchange Server检索WDSL后使用SoapUI生成的:
<?xml version="1.0"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:typ="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:mes="http://schemas.microsoft.com/exchange/services/2006/messages">
<soapenv:Header><typ:RequestServerVersion Version="Exchange2010"/></soapenv:Header>
<soapenv:Body>
<mes:ResolveNames ReturnFullContactData="1" SearchScope="ActiveDirectoryContacts">
<mes:UnresolvedEntry>deve</mes:UnresolvedEntry>
</mes:ResolveNames>
</soapenv:Body>
</soapenv:Envelope>
这是我使用的裸Delphi XE2代码:
procedure TFrmTestEWS.BtnConnectClick(Sender: TObject);
var
lESB : ExchangeServicePortType;
lResNames : ResolveNames;
lReqVersion : RequestServerVersion;
lResResult : ResolveNamesResponse;
lServerVer : ServerVersionInfo;
lUnresolved : String;
begin
lServerVer := ServerVersionInfo.Create;
lResNames := ResolveNames.Create;
lReqVersion := RequestServerVersion.Create;
lUnresolved := 'Deve';
with lResNames do
begin
ReturnFullContactData := true;
SearchScope := ResolveNamesSearchScopeType.ActiveDirectoryContacts; // Scoped enums is on!
ParentFolderIds := nil;
UnresolvedEntry := lUnresolved;
end;
lReqVersion.Version := ExchangeVersionType.Exchange2010;
lESB := (HTTPRIO1 as ExchangeServicePortType);
lESB.ResolveNames(lResNames,
nil, // Impersonation
nil, // MailboxCulture
lReqVersion,
lResResult,
lServerVer);
它生成:
<?xml version="1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body xmlns:NS1="http://schemas.microsoft.com/exchange/services/2006/types">
<ResolveNames xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" ReturnFullContactData="true" NS1:SearchScope="ActiveDirectoryContacts">
<UnresolvedEntry>deve</UnresolvedEntry>
</ResolveNames>
<MailboxCulture xsi:nil="true"/>
<ExchangeImpersonation xsi:nil="true"/>
<NS1:RequestServerVersion Version="Exchange2010"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
我得到的错误:
请求未通过架构验证:未声明“http://schemas.microsoft.com/exchange/services/2006/types:SearchScope”属性。
SearchScope是messages.xsd中定义的属性:
<!-- ResolveNames request -->
<xs:complexType name="ResolveNamesType">
<xs:complexContent>
<xs:extension base="m:BaseRequestType">
<xs:sequence>
<xs:element name="ParentFolderIds" type="t:NonEmptyArrayOfBaseFolderIdsType" minOccurs="0"/>
<xs:element name="UnresolvedEntry" type="t:NonEmptyStringType"/>
</xs:sequence>
<xs:attribute name="ReturnFullContactData" type="xs:boolean" use="required"/>
<xs:attribute name="SearchScope" type="t:ResolveNamesSearchScopeType" default="ActiveDirectoryContacts"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="ResolveNames" type="m:ResolveNamesType"/>
with types.xsd:
<!-- ResolveNames request -->
<xs:simpleType name="ResolveNamesSearchScopeType">
<xs:restriction base="xs:string">
<xs:enumeration value="ActiveDirectory"/>
<xs:enumeration value="ActiveDirectoryContacts"/>
<xs:enumeration value="Contacts"/>
<xs:enumeration value="ContactsActiveDirectory"/>
</xs:restriction>
</xs:simpleType>
我认为NS1:SearchScope =“ActiveDirectoryContacts”不正确但离开NS1:out会出现同样的错误。
也许将类型和消息的Exchange xmlns规范推迟到SOAP-ENV:Body中是出错的原因?
此外,NS1:RequestServerVersion Version =“Exchange2010”不在SOAP_ENV:Header中
看起来很可疑。
我查看了some Google results,但无法让它发挥作用。
基本上我的问题是:
如何在生成的代码中移动标记或xmlns属性直到它工作,而不必自己构建整个SOAP?
如果那是不可能的,哪种方法最好,这样我仍然可以从导入的类型库中受益? (像this这样的东西?)
感谢
扬
答案 0 :(得分:1)
我决定不尝试修复特定的XML标记,而是完全控制出来的SOAP内容:
我只是在TStringStream中构建XML,然后在HTTPRIO.BeforeExecute中将TStringStream内容放入SOAPStream中。
安装SOAPUI后,我可以导入WDSL,然后“手动”生成并测试所需的SOAP调用。完成后,我将它们移到Delphi代码中
这给了我一个优势,即仍然可以访问WDSL生成的代码来解析结果(无需深入研究返回的XML)。
这是代码,它显示了旧方法(BtnConnectClick)和新方法(BtnAlternateClick)。
unit uTestEWS;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls,TypInfo, WinAPI.WinInet,
Soap.Rio, Soap.InvokeRegistry, Soap.SOAPHTTPClient, Soap.SOAPHTTPTrans,
services { = The file generated from the WDSL };
type
TFrmTestEWS = class(TForm)
HTTPRIO: THTTPRIO;
Panel1: TPanel;
MmoLog: TMemo;
TV: TTreeView;
MmoResult: TMemo;
BtnConnect: TButton;
BtnAlternate: TButton;
Memo1: TMemo;
Label1: TLabel;
procedure HTTPRIOBeforeExecute(const MethodName: string;
SOAPRequest: TStream);
procedure HTTPRIOAfterExecute(const MethodName: string;
SOAPResponse: TStream);
procedure BtnConnectClick(Sender: TObject);
procedure HTTPRIO1HTTPWebNode1BeforePost(const HTTPReqResp: THTTPReqResp;
Data: Pointer);
procedure BtnAlternateClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FSoapData: TStringStream;
procedure Res(Msg: String);
procedure InitializeSoapData;
procedure FinalizeSoapData;
public
end;
var
FrmTestEWS: TFrmTestEWS;
implementation
{$R *.dfm}
procedure TFrmTestEWS.BtnConnectClick(Sender: TObject);
var
lESB : ExchangeServicePortType;
lResNames : ResolveNames;
lReqVersion : RequestServerVersion;
lResResult : ResolveNamesResponse;
lServerVer : ServerVersionInfo;
begin
lServerVer := ServerVersionInfo.Create;
lResNames := ResolveNames.Create;
lReqVersion := RequestServerVersion.Create;
lResResult := ResolveNamesResponse.Create;
try
try
// 1. Setup
(* Replaced by alternate, see BtnAlternateClick
lUnresolved := 'deve';
with lResNames do
begin
ReturnFullContactData := true;
SearchScope := ResolveNamesSearchScopeType.ActiveDirectoryContacts; // Scoped enums is on!
ParentFolderIds := nil;
UnresolvedEntry := lUnresolved;
end;
lReqVersion.Version := ExchangeVersionType.Exchange2010;
*)
// 2. Execute
lESB := (HTTPRIO as ExchangeServicePortType);
lESB.ResolveNames(lResNames,
nil, // Impersonation
nil, // MailboxCulture
lReqVersion,
lResResult,
lServerVer);
// 3. Report
MmoResult.Clear;
Res('Server version:');
with lServerVer do
begin
Res(' MajorVersion: ' + IntToStr(MajorVersion));
Res(' MinorVersion: ' + IntToStr(MinorVersion));
Res(' MajorBuildNumber: ' + IntToStr(MajorBuildNumber));
Res(' MinorBuildNumber: ' + IntToStr(MinorBuildNumber));
Res(' Version: ' + Version);
end;
// [ snip rest of code not relevant for this example]
except
on E:Exception do MmoResult.Text := E.Message;
end;
finally
// 4. Clean up
lResResult.Free;
lServerVer.Free;
lReqVersion.Free;
lResNames.free;
LESB := nil;
end;
end;
procedure TFrmTestEWS.FormCreate(Sender: TObject);
begin
FSoapData := TStringStream.Create('',TEncoding.UTF8);
FSoapData.Position := 0;
end;
procedure TFrmTestEWS.FormDestroy(Sender: TObject);
begin
FSoapData.Free;
end;
procedure TFrmTestEWS.HTTPRIOAfterExecute(const MethodName: string;
SOAPResponse: TStream);
var
TS: TStringStream;
S : String;
begin
S := MmoLog.Text + #13#10#13#10 + 'Response:' + #13#10#13#10;
TS := TStringStream.Create(S);
TS.Position := Length(S);
SOAPResponse.Position := 0;
TS.CopyFrom(SOAPResponse,SOAPResponse.Size);
TS.Position := 0;
MmoLog.Lines.LoadFromStream(TS);
TS.Free;
end;
procedure TFrmTestEWS.HTTPRIOBeforeExecute(const MethodName: string;
SOAPRequest: TStream);
begin
// 1. Alternate approach
SOAPRequest.Position := 0;
FSoapData.Position := 0;
SOAPRequest.CopyFrom(FSoapData,FSoapData.Size);
SOAPRequest.Size := FSoapData.Size;
// 2. Logging
MmoLog.Clear;
MmoLog.Lines.Add('Request:' + #13#10#13#10);
FSoapData.Position := 0;
MmoLog.Lines.LoadFromStream(FSoapData);
end;
procedure TFrmTestEWS.InitializeSoapData;
begin
FSoapData.Clear;
FSoapData.WriteString('<soapenv:Envelope');
FSoapData.WriteString(' xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"');
FSoapData.WriteString(' xmlns:typ="http://schemas.microsoft.com/exchange/services/2006/types"');
FSoapData.WriteString(' xmlns:mes="http://schemas.microsoft.com/exchange/services/2006/messages">');
FSoapData.WriteString('<soapenv:Header><typ:RequestServerVersion Version="Exchange2010"/></soapenv:Header>');
FSoapData.WriteString('<soapenv:Body>');
end;
procedure TFrmTestEWS.FinalizeSoapData;
begin
FSoapData.WriteString('</soapenv:Body>');
FSoapData.WriteString('</soapenv:Envelope>');
end;
procedure TFrmTestEWS.BtnAlternateClick(Sender: TObject);
begin
InitializeSoapData;
FSoapData.WriteString(' <mes:ResolveNames ReturnFullContactData="1" SearchScope="ActiveDirectoryContacts">');
FSoapData.WriteString(' <mes:UnresolvedEntry>deve</mes:UnresolvedEntry>');
FSoapData.WriteString(' </mes:ResolveNames>');
FinalizeSoapData;
// Pick up from first attempt 'execute':
BtnConnectClick(Sender);
end;
procedure TFrmTestEWS.HTTPRIO1HTTPWebNode1BeforePost(
const HTTPReqResp: THTTPReqResp; Data: Pointer);
const
CONTENT_HEADER_EX2010 = 'Content-Type: text/xml; charset=utf-8';
begin
// http://forum.delphi-treff.de/archive/index.php/t-31817.html
// Need to exchange the Content-Type Header, because Exchange 2010 expects
// 'Content-Type: text/xml; charset=utf-8' instead of
// 'Content-Type: text/xml; charset="utf-8"' which is RFC conform and used by XE2
HttpAddRequestHeaders(Data, PChar(CONTENT_HEADER_EX2010), Length(CONTENT_HEADER_EX2010), HTTP_ADDREQ_FLAG_REPLACE);
end;
procedure TFrmTestEWS.Res(Msg: String);
begin
MmoResult.Lines.Add(Msg);
end;
end.