Estoy usando Delphi XE2 para comunicarme con un servicio SOAP bastante grande. He importado con éxito el wsdl y todo está funcionando bien. Sin embargo, me encuentro escribiendo un código similar. Me gustaría tener un método genérico que llame a mi servicio web. También me resulta difícil leer varias veces mi código tal como está ahora, ya que tengo que escribir tanto código para cada tipo de llamada.Invocando dinámicamente un método SOAP por su nombre?
Siendo más como programador de fin de semana, estoy lejos de dominar los entresijos de Delphi, pero creo que al menos tengo una comprensión justa de RTTI, que creo que debe usarse para hacer lo que quiero.
El servicio web tiene alrededor de 700 métodos diferentes y ese es prácticamente el problema. El código generado a partir del WSDL tiene métodos de la siguiente manera:
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
Básicamente, hay alrededor de 700 diferentes tipos de cosas que se pueden manejar, y no añadir, actualizar, obtener, quitar y list-métodos para todos ellos . Con cada llamada, hay una clase correspondiente que se usa como parámetros para la solicitud SOAP. También hay una clase correspondiente para la respuesta, como puede ver arriba.
Las clases se vería algo así como (muy simplificada):
addStuff = class
private
FStuff: string;
published
property stuff: string Index (IS_UNQL) read FStuff write FStuff;
end;
Así que cuando llamo al servicio web que hago por ejemplo:
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;
(Sí, ya sé que debería haber intento ..finally y gratis allí también :-))
Luego, en algún otro lugar del código, necesito llamar a un método diferente:
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;
Como sé que el parámetro siempre es una clase con un nombre que es equivalente al método que llamo, me gustaría poder hacer algo como el metacódigo siguiente para invocar dinámicamente la llamada. Supongo que requiere un poco de magia RTTI pero have'nt sido capaz de encontrar una manera de hacerlo:
procedure soapRequest(Param: Something; var Response: Something);
begin
soap := GetMyWebServicePort(false,'',nil);
Response := soap.DynamicInvoke(Param.ClassName, Param);
end
entonces yo podría hacer algo como:
soapRequest(VarOfTypeAddStuff,VarOfTypeAddStuffResponse)
soapRequest(VarOfTypeListStuff,VarOfTypeListStuffResponse)
...
¿Alguien tiene una idea de cómo mi las llamadas al servicio web se pueden simplificar?
Será interesante ver si alguien se le ocurre tal, sino que acabo de escribir rutinas de envoltura como que tiene "ocultar" los detalles. – mj2008
@dahook: primera publicación muy bien escrita. Votado arriba. Bienvenido a SO. – RobertFrank