1

これは、Exchange Server から WDSL を取得した後にSoapUIで生成したEWSでResolveNames を呼び出すサンプル コードです。

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

エラー:

The request failed schema validation: The ' 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 を残すと同じエラーが発生します。
おそらく、型とメッセージの Exchange xmlns 仕様を SOAP-ENV:Body 内に延期することがエラーの理由ですか?
また、SOAP_ENV:Header に含まれていない NS1:RequestServerVersion Version="Exchange2010" が疑わしいようです。

私はいくつかの Google の結果を見てきましたが、それを機能させることができませんでした。

基本的に私の質問は次のとおりです
。SOAP 全体を自分で構築することなく、生成されたコード内のタグまたは xmlns 属性を動作するまでどのように移動できますか?
それが不可能な場合、インポートされたタイプ ライブラリを引き続き利用できるようにするには、どのようなアプローチが最適ですか? (こんなもの

ありがとう
ヤン

4

1 に答える 1

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.
于 2012-10-31T12:41:42.593 に答える