2012-10-30 41 views
1

這是工作示例代碼調用ResolveNames在我SoapUI生成從Exchange Server檢索WDSL後EWS「屬性未聲明」在德爾福錯誤產生的EWS SOAP請求

<?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> 

這是裸德爾福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"/> 

在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給出相同的錯誤。
也許推遲了類型和消息交易所的xmlns規範提交給SOAP-ENV中:身體是該錯誤的原因是什麼?
此外,NS1:RequestServerVersion版本=「Exchange2010」不在SOAP_ENV:標題 中,這看起來有些可疑。

我看過someGoogle results但無法使其正常工作。

基本上我的問題是:
如何在生成的代碼中移動標籤或xmlns屬性直到它工作,而無需自己構造整個SOAP?
如果這是不可能的哪種方法最好,這樣我仍然可以從導入的類型庫中獲益? (東西一樣this?)

謝謝

回答

1

我決定不嘗試解決特定的XML標籤,但接管SOAP內容完全控制外出:
我只是建立在XML中一個TStringStream,然後在HTTPRIO.BeforeExecute我把TStringStream內容到SOAPStream。
隨着SOAPUI安裝,我可以導入W​​DSL,然後產生和「通過手」測試所需的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.