2012-06-28 22 views
14

私はかなり大きなSOAPサービスと通信するためにDelphi XE2を使用しています。私は正常にwsdlをインポートし、すべてがうまく動作しています。しかし、私は同じようなコードをたくさん書いています。私は私のWebサービスを呼び出すジェネリックメソッドを持っていたいと思います。私はまた、今のように私のコードをマルチスレッド化するのは難しいと思います。なぜなら、私は各タイプの呼び出しごとにあまりにも多くのコードを書く必要があるからです。名前でSOAPメソッドを動的に呼び出す?

私は週末のプログラマーの方が多いので、デルファイの出入り口を習得するのは遠いですが、私は少なくとも私が望むことをするために使用しなければならないRTTIを公正に理解していると思います。

Webサービスには約700種類のメソッドがあり、それはかなり問題です。 WSDLから生成されたコードは以下のような方法があります。基本的には

function addPhone(const Params: addPhone): addPhoneResponse; stdcall; 
function updatePhone(const Params: updatePhone): updatePhoneResponse; stdcall; 
function getPhone(const Params: getPhone): getPhoneResponse; stdcall; 
function removePhone(const Params: removePhone): removePhoneResponse; stdcall; 
function listPhone(const Params: listPhone): listPhoneResponse; stdcall; 
function addStuff(const Params: addStuff): addStuffResponse; stdcall; 
function updateStuff(const Params: updateStuff): updateStuffResponse; stdcall; 
... 
... about 700 more of the above 

、処理することができるものの約700の異なるタイプがあり、そしてそれらすべてのために、更新、追加、取得、削除、およびリストの方法があります。呼び出しごとに、対応するクラスがSOAPリクエストのパラメータとして使用されます。上記のように、対応するクラスもあります。

クラスは(非常に単純化された)のようになります。

addStuff = class 
    private 
    FStuff: string; 
    published 
    property stuff: string Index (IS_UNQL) read FStuff write FStuff; 
    end; 

私は、Webサービスを呼び出すときに、私は、たとえば行います

procedure CreateStuff; 
var 
    req: addStuff; 
    res: addStuffResponse; 
    soap: MyWebServicePort; 
begin 
    // Use the function in the wsdl-generated code to create HTTPRIO 
    soap := GetMyWebServicePort(false,'',nil); 
    // Create Parameter Object 
    req := addPhone.Create; 
    req.stuff := 'test'; 
    // Send the SOAP Request 
    res := soap.addStuff(req); 
end; 

(はい、私は試してみる必要があります知っています..finally and Free in there :-))

コード内のどこか別のメソッドを呼び出す必要があります。

procedure listStuff; 
var 
    req: listStuff; 
    res: listStuffResponse; 
    soap: MyWebServicePort; 
begin 
    // Use the function in the wsdl-generated code to create HTTPRIO 
    soap := GetMyWebServicePort(false,'',nil); 
    // Create Parameter Object 
    req := listPhone.Create; 
    req.stuff := 'test2'; 
    // Send the SOAP Request 
    res := soap.listStuff(req); 
end; 

私はパラメータが常に私が呼び出すメソッドに相当する名前のクラスであることを知っているので、私は動的に呼び出しを呼び出すために以下のメタコードのようにすることができます。私はそれはいくつかのRTTIの魔法を必要と推測するが、私はそれを行うための方法を見つけることができたhave'nt:誰がどのように私のアイデアを持っています

soapRequest(VarOfTypeAddStuff,VarOfTypeAddStuffResponse) 
soapRequest(VarOfTypeListStuff,VarOfTypeListStuffResponse) 
... 

procedure soapRequest(Param: Something; var Response: Something); 
begin 
    soap := GetMyWebServicePort(false,'',nil); 
    Response := soap.DynamicInvoke(Param.ClassName, Param); 
end 

その後、私はのような何かを行うことができますWebサービスへの呼び出しを簡素化できますか?

+0

誰もがそのような思い付くかどうかを確認するために興味深いものになるが、あなたを「隠す」の詳細を持っているように私は単なるラッパー・ルーチンを書きました。 – mj2008

+3

@dahook:非常にうまく書かれた最初の投稿。投票した。ようこそ。 – RobertFrank

答えて

4

私は何週間も自分自身を解決しようとしていた質問を投稿してからほんの数時間後に突然ただ自分で解決することができたのは本当に奇妙です...私はSOを巡ってインスピレーションを得ました。私は道に沿って私を助けたこれを見つけた:Delphi - Invoke Record method per name

私のシナリオは、メソッド自体と同じクラス名を持つパラメータを持つメソッドを呼び出すので、いくらか具体的です。私はパブリックWebサービスと通信する簡単なバージョンも書いています。誰かが興味を持っているなら、あなたはここにそのコードを得ることができます:http://www.hook.se/delphi/SoapDynamicInvoke.zip。動的なメソッド呼び出しを行うのは、Webサービスに多くの異なるメソッドがある場合にのみ関係するため、役に立たない例です。それにもかかわらず、誰かにとって興味深いかもしれません:-)

以下は私のWebサービスでこれをどのように解決したかです。言われたように、それは非常に具体的であり、コードはより一般的にすることができますが、これは私のために働く。

このメソッドはTRemotableオブジェクトで呼び出され、オブジェクトのクラス名と同じ名前のメソッドで呼び出されます。

function soapRequest(Param: TRemotable): TValue; 
var 
    soap: AXLPort; 
    C: TRttiContext; 
    T: TRttiType; 
    M: TRttiMethod; 
    SoapParam: TArray<TValue>; 
    TVres: TValue; 
    soap: MyWebServicePort; 
begin 
    // Use the function in the wsdl-generated code to create HTTPRIO 
    soap := GetMyWebServicePort(false,'',nil); C := TRttiContext.Create; 
    T := C.FindType('MyWebService.MyWebServicePort'); 
    M := T.GetMethod(Param.ClassName); 
    SetLength(SoapParam,1); 
    SoapParam[0] := TValue.From(Param); 
    TVres := M.Invoke(TValue.From<IInterface>(soap), SoapParam); 
    Result := TVres; 
end; 

上記の機能を使用するには:

procedure DoSomeSoapCalls(Sender: TObject); 
var 
    req1: getStuff 
    res1: getStuffResponse; 
    req2: addStuff; 
    res2: addStuffResponse; 
    res: TValue; 
begin 
    //Request #1 
    req1 := getStuff.Create; 
    req1.stuffToGet := 'abc'; 
    try 
    res := soapRequest(req1); 
    res1 := getStuffResponse(res.AsObject); 
    finally 
    req1.Free; 
    end; 
    Writeln(res1.someproperty); 
    FreeAndNil(res1); 

    //Request #2 
    req2 := addStuff.Create; 
    req2.StuffToAdd := 'cde'; 
    try 
    res := soapRequest(req2); 
    res2 := addStuffResponse(res.AsObject); 
    finally 
    req2.Free; 
    end; 
    Writeln(res2.result); 
    FreeAndNil(res2); 
end; 

あり、必要な型キャストのビットですが、私の場合は私が、私はそれでかなり安全であると思います。誰にもこれに関する他のコメント/提案がありますか?つまり、これは機能しますが、おそらくそれを強化する方法があります。

乾杯、

ダン

関連する問題