2012-06-28 48 views
14

我使用德爾福XE2有相當大的SOAP服務進行通信。我已經成功導入了wsdl,一切正常。但是,我發現自己寫了很多類似的代碼。我想要一個調用我的Web服務的通用方法。我也發現現在很難多線程化我的代碼,因爲我必須爲每種類型的調用編寫這麼多的代碼。動態地按名稱調用SOAP方法?

作爲一名週末程序員,我遠離掌握Delphi的進出,但我認爲我至少對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和免費在那裏以及:-))

然後,代碼中的其他地方我需要調用不同的方法:

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能找到一個方法來做到這一點:

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

然後,我可以做這樣的事情:

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

有沒有人有一個想法如何我對web服務的調用可以簡化?

+0

這將是有趣的,看看是否有人想出了這樣的,但我只是寫了包裝程序就像你有「隱藏」的細節。 – mj2008

+3

@dahook:非常好寫的第一篇文章。投了票。歡迎來到SO。 – RobertFrank

回答

4

這很古怪,我只是發表我一直在試圖解決自己對周突然一下就由我自己解決的問題後幾個小時......我的靈感來自於SO四處尋找,並我發現這幫助了我:Delphi - Invoke Record method per name

我的情況我有點特殊,因爲我打電話與具有相同的類名作爲方法本身的參數的方法。我還寫了一個與公共Web服務進行通信的更簡單的版本。如果有人感興趣,您可以在這裏獲得該代碼:http://www.hook.se/delphi/SoapDynamicInvoke.zip。這是一個沒用的例子,因爲動態方法調用只有在Web服務有很多不同的方法時才適用。然而,它可能是有趣的人:-)

下面是我如何解決這個對我的Web服務。如上所述,這是非常具體的,代碼可以更通用,但這對我很有用。

用TRemotable對象調用此方法,然後使用與對象的類名相同的名稱調用Web服務。

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; 

有一點必要的類型轉換的,但在我的情況下,我認爲我會與非常安全的。有沒有人對此有任何其他意見/建議?我的意思是,這有效,但可能有方法來加強它。

乾杯,

相關問題