segunda-feira, 8 de setembro de 2008

Webservice no BDS2006

Observamos que o assunto "WebService em Delphi" tem tido muita procura aqui no blog. Por isso, pretendo produzir mais material sobre este tema. Contudo, o assunto é abrange um escopo bastante vasto, principalmente no que tange as questões práticas do desenvolvimento de serviços baseados em XML/SOAP. Podemos citar para exemplificar alguns temas sobre “WebService e Delphi”: Testar as versões mais recentes (inclusive o Tiburon – Delphi 2009), verificar incompatibilidades (se existirem), ou diferenças. Uma coisa interessante seria a integração com outras tecnologias (Java, C# e PHP, por exemplo). Outro ponto importante: Acesso e disponibilização de dados (um CRUD, talvez, usando como camada intermediária um aplicação servidora WS). Em fim, há bastante terreno para ser trabalhado.
Neste sentido, podemos eventualmente atender alguma questão pontual demandada pelos leitores. Coloque em forma de comentários sua demanda que na medida do possível teremos prazer em atendê-la. Algumas pessoas já solicitam nosso suporte, informalmente, via e-mail. Porém, seria melhor que além do e-mail o comentário sobre a demanda fosse registrado. Pois, dessa forma aproveitamos a resolução do seu problema para conteúdo do blog. Assim, outros que por ventura vierem até nós com problemas semelhantes possam compartilhar da solução sem gerar retrabalho para nós. Conseqüentemente, imagino que nosso conteúdo será mais aderente. Isso é o que de fato nos importa.

Iniciando um novo projeto

No BDS2006 no menu File ►New ► Other ► Delphi Projects ►WebServices, selecione “SOAP Server Application”. Em seguida uma série de configurações prévias serão feitas mediante alguns diálogos.



No diálogo seguinte selecione ISAPI/NSAPI Dynamic Link Library, e click em “OK”.



Click “Yes” para criar a interface do serviço (WSDL). Veja imagem abaixo:



No próximo diálogo definiremos o nome do serviço que estamos criando: “ZnShowMeTheMoney”, conforme ilustrado abaixo.



Pronto, temos um novo projeto! Estamos desenvolvendo uma aplicação servidora. Um WebService, veja as units que foram cridas na inicialização do nosso projeto:



A lógica sobre declarações nas units, num projeto WebService: Existe uma unit para declarações de interface e uma unit para as implementarmos o que declararemos na unit interface (neste caso temos: “ZnShowMeTheMoneyIntf”, interface. “ZnShowMeTheMoneyImpl”, implementação).

Na interface declararemos uma função. Digite conforme ilustrado abaixo:


(* Declarando uma funcionalidade no serviço que estamos criando *)
function ZnShowMeTheMoney: WideString; stdcall;

A seguir, veja como ficou a unit “ZnShowMeTheMoneyIntf”.

{ Invokable interface IZnShowMeTheMoney }

unit ZnShowMeTheMoneyIntf;

interface

uses InvokeRegistry, Types, XSBuiltIns;

type

{ Invokable interfaces must derive from IInvokable }
IZnShowMeTheMoney = interface(IInvokable)
['{F002F904-9FD7-401D-80E2-037DFFAA4590}']

{ Methods of Invokable interface must not use the default }
{ calling convention; stdcall is recommended }
(* Declarando uma funcionalidade no serviço que estamos criando *)
function ZnShowMeTheMoney: WideString; stdcall;
end;

implementation

initialization
{ Invokable interfaces must be registered }
InvRegistry.RegisterInterface(TypeInfo(IZnShowMeTheMoney));

end.


Agora para implementarmos iremos fazê-lo na unit “ZnShowMeTheMoneyImpl”. Digite conforme ilustrado no trecho de código asseguir:

type

{ TZnShowMeTheMoney }
TZnShowMeTheMoney = class(TInvokableClass, IZnShowMeTheMoney)
public
(* Na unit de implementação precisamos digitar novamente a assinatura do
método que declaramos na interface "ZnShowMeTheMoneyIntf" *)
function ZnShowMeTheMoney: WideString; stdcall;
end;

implementation


Declare uma seção “uses” após a palavra reservada “implementation” e declare as bibliotecas: Math e SysUtils.

OBS: No BDS temos code insight para declaração de bibliotecas!!!



Vamos implementar o método declarado na seção public de “TZnShowMeTheMoney”.

function TZnShowMeTheMoney.ZnShowMeTheMoney: WideString;
const
ZnMsgConst = 'Here is your Money, U$ %f! Do you can see him? look at the message ... ';
var
RandomValue: Double;
RandomDiv: Integer;
begin
RandomValue := RandomRange(1, 10000);
RandomDiv := RandomRange(1, 7);
RandomValue := (RandomValue / RandomDiv);

Result := Format(ZnMsgConst, [RandomValue]);
end


A função que acabamos de codificar, “ZnShowMeTheMoney”, é simplesmente um processamento dummy que retorna aleatoriamente dois valores, os quais são usados como operandos numa divisão cujo o resultado é formatado numa string e retornado na função.
Agora vamos salvar a aplicação, veja ilustração abaixo:




Para o nome do projeto vamos usar “PrjZNShowMoney.bdsproj”. A imagem seguinte mostra, o meu “Project Manager”, para que você possa compara a estrutura do seu projeto com o andamento do nosso exemplo.



Agora vamos publicar nosso serviço: Compile o projeto, em seguida faça o deploy da DLL, “PrjZNShowMoney.dll”, no IIS.

Criei um diretório virtual com alias de “WsShowMeTheMoneyZn”. Para testar, no browser digite: http://localhost/wsshowmethemoneyzn/

Click no link WSDL e você acessará a interface do serviço “IZnShowMeTheMoneyservice”, isso que você esta vendo é mais que uma página web comum.




Neste primeiro exemplo podemos concluir que o desenvolvimento em WS no BDS2006 é semelhante ao do Delphi 7.
É Muito rápido, intuitivo e amigável desenvolver serviços RPC baseados em SOAP/XML no DBS2006, desde que você conheça bem três conceitos:

1 - A estrutura de declarações no Delphi.

2 - Calling Conventions: Convenções de chamadas (traduziremos assim)- Quando declaramos procedimentos ou funções podemos definir, neste momento, a convenção de chamada através das diretivas: register, pascal, cdecl, stdcall, and safecall.
Por exemplo:

function ZNFuncao(const Xzn, Yzn: Double): Double; cdecl;

function ZNProcedimento(const Xzn, Yzn: Double; var AoutZn: Double); stdcall;

3- Sistemas distribuídos: Também chamado na literatura de objetos distribuídos.

Outros artigos sobre Webservice e Delphi

2 comentários:

  1. Esse exemplo roda blz, mas quando envolvo banco de dados no meio é que não roda. to colocando um ADOConnection e um Adoquery no WebModule pra fazer uma consulta. Quando o cliente chama a função q faz esse acesso ao banco ele dar erro no arquivo dll. alguem sabe como resolver isto?

    ResponderExcluir
  2. Esta DLL gerada pelo delphi é compatível com qualquer servidor web?
    O exemplo cita o IIS, mas é compatível com apache por exemplo?

    ResponderExcluir