Protheus :: Rompendo Limites e Barreiras (open your mind)
Rodrigo entrou em uma roubada. Perguntou-me: "..иαldσ estou com problemas para gerar um client de um WebService no Protheus, não sei se é minha instalação. Será que você poderia me ajudar?" (foi + ou - assim ... rs)
manda-o-link-aew (respondi eu). e;
taí: http://201.48.221.162:2000/ServiceFuturePMS/service?WSDL
Testei.... hummmmm.... Olha a mensagem emitida pelo IDE:
Estabelecendo conexão com o server... Por favor aguarde. Obtendo descrição do WebService... Erro na obtenção da descrição do WebService: Invalid function return for WSDLSource Call. Finalizando conexão com o server... Ok
Bem... não me ajudou muito.... Opa.... "Invalid function return for WSDLSource Call".... hummmmmm.... WSDLSource... acho que é esse carinha aqui quem tenta gerar o client.... Vamos executá-lo diretamente.... Sintaxe: WSDLSource( cUrl ) : [lSucess][cSource/cError].
Retorno NIL, estava eperando um Array.... Vamos ver o Console do server...
WSDLSource( "http://201.48.221.162:2000/ServiceFuturePMS/service?WSDL" ) NIL
[FATAL][SERVER] [Thread 1356] [THROW] String size overflow! at file c:\advtec9_101202a\lib_base\stringz.hpp line 355
String size overflow! (Oops: Erro, erro no servidor, Bad, bad server ).....
Rodrigo, seguinte, o protheus "p...". A restrição no tamanho da string imposta pelo pessoal de Tecnologia do Protheus não vai deixar que gere o seu Client.
Tem alguma solução? (perguntou ele).... e a resposta foi: 3 Possíveis soluções.
1 ) Abrir um chamado da Totvs/Microsiga e solicitar que ampliem o limite da string;
2 ) Entrar em contato com o Desenvolvedor do WebService e pedir para que ele divida o WS em Vários outros WS ; e
3 ) Usar uma aplicação externa para resolver o WS e retornar a informação ao Protheus. Testei no Windows® PowerShell® e funciona que é uma beleza.
O que acha?
"O pessoal aqui não acredita que essa ultima solução funcione. Tem como mandar um exemplo simples? Tem o Método CountUsers que retorna o número de usuários."....
heheheheh.... demorô.....
Segue o Código:
#INCLUDE "APWEBSRV.CH" #INCLUDE "PROTHEUS.CH" #INCLUDE "TRYEXCEPTION.CH" /*/ WSSERVICE: u_FuturePMS Autor: Marinaldo de Jesus Data: 05/05/2011 Descricao: Usar PowerShell para Resolver WS nao suportado pelo Protheus em Funcao de Limitacao da Linguagem /*/ WSSERVICE u_FuturePMS DESCRIPTION "Integracao Protheus x PowerShell x FuturePMS" NAMESPACE "http://localhost/u_futurepms.apw" WSDATA CountUser AS INTEGER WSDATA PSException AS BOOLEAN WSMETHOD CountUsers DESCRIPTION "Retornar o Numero de Usuarios do ServiceFuturePMS" ENDWSSERVICE /*/ WSMETHOD: CountUsers Autor: Marinaldo de Jesus Data: 05/05/2011 Descricao: Encapsular a Chamada ao Metodo CountUsers do WS ServiceFuturePMS executando-o atraves do PS e retornando o Resultado /*/ WSMETHOD CountUsers WSRECEIVE PSException WSSEND CountUser WSSERVICE u_FuturePMS Local aFileErase := {} Local cCRLF := CRLF Local cPsHome := "" Local cPsScript := "" Local cRootPath := "" Local cPSFileSript := "" Local cPathFileXml := "" Local cFullPathXml := "" Local cFullPathPS1 := "" Local cWsResultPath := "\PPSIntWs\" Local cWSFileResult := "" Local cXmlError := "" Local cXmlWarning := "" Local lWsMethodRet := .T. Local oXml Local oException TRYEXCEPTION cRootPath := GetSrvProfString( "RootPath" , "" ) IF ( SubStr( cRootPath , -1 ) == "\" ) cRootPath := SubStr( cRootPath , 1 , Len( cRootPath ) - 1 ) EndIF IF !lIsDir( cWsResultPath ) MakeDir( cWsResultPath ) IF !lIsDir( cWsResultPath ) ExUserException( "Impossível Criar o Diretório: " + cWsResultPath ) EndIF EndIF cWSFileResult := CriaTrab( NIL , .F. ) cPathFileXml := ( cWsResultPath + cWSFileResult ) While ( File( cPathFileXml + ".xml" ) .or. File( cPathFileXml + ".ps1" ) ) cWSFileResult := CriaTrab( NIL , .F. ) cPathFileXml := ( cWsResultPath + cWSFileResult ) End While cPSFileSript := ( cWSFileResult + ".ps1" ) cPathFileXml += ".xml" aAdd( aFileErase , cPathFileXml ) cFullPathXml := ( cRootPath + cPathFileXml ) cPSFileSript := ( cWsResultPath + cPSFileSript ) cFullPathPS1 := ( cRootPath + cPSFileSript ) aAdd( aFileErase , cPSFileSript ) DEFAULT Self:PSException := .F. DEFAULT PSException := Self:PSException /*/ Para que o "script" possa ser executado faz-se necessario autoriza-lo atraves do Windows PowerShell, sendo assim, execute o Windows PowerShell e digite o seguinte comando: get-help about_signing. Esse comando ira listar as opcoes de "Diretivas de Assinatura e de Execucao" de "Script". Leia-as atentamente. Mas se quiser pular esse passo (eu nao recomendo) digite o seguinte comando abaixo no Windows PowerShell: Set-ExecutionPolicy Unrestricted. Esse comando fara que qualquer "Script" seja executado em sua máquina (mas atente para os itens de seguranca listados aa partir do comando get-help about_signing). /*/ cPsScript := " [int]$CountUserResult = 0" cPsScript += cCRLF cPsScript += " [boolean]$CountUserResultSpecified = $True" cPsScript += cCRLF cPsScript += " $ws = New-WebServiceProxy -URI http://201.48.221.162:2000/ServiceFuturePMS/service?WSDL" cPsScript += cCRLF cPsScript += " $ws.CountUsers( [ref]$CountUserResult , [ref]$CountUserResultSpecified )" cPsScript += cCRLF cPsScript += " [string]$PSOutFile = '" + cFullPathXml + "'" cPsScript += cCRLF cPsScript += " $xml = " + '"' + "" + '"' cPsScript += cCRLF cPsScript += " $xml | Out-File $PSOutFile" cPsScript += cCRLF IF ( PSException ) cPsScript := AddPsException( @cPsScript , @cCRLF ) EndIF MemoWrite( cPSFileSript , cPsScript ) cPsHome := AllTrim( GetSrvProfString( "PSHome" , "C:\WINDOWS\system32\WindowsPowerShell\v1.0\" ) ) IF !( SubStr( cPsHome , -1 ) == "\" ) cPsHome += "\" EndIF IF !( WaitRunSrv( cPsHome + "powershell.exe " + cFullPathPS1 , .T. , cPsHome ) ) ExUserException( "Impossivel Executar o PowerShell" ) EndIF IF !File( cPathFileXml ) ExUserException( "XML não carregado: " + cPathFileXml ) EndIF oXml := XmlParserFile( @cPathFileXml , "_" , @cXmlError , @cXmlWarning ) IF !( ValType( oXml ) == "O" ) IF !Empty( cXmlError ) ExUserException( cXmlError ) EndIF ExUserException( "Impossovel Carregar o XML: " + cPathFileXml ) EndIF Self:CountUser := Val( oXml:_Result:_CountUser:Text ) CountUser := Self:CountUser CATCHEXCEPTION USING oException lWsMethodRet := .F. SetSoapFault( ProcName() , CaptureError() ) ENDEXCEPTION aEval( aFileErase , { |cFile| IF( File( cFile ) , fErase( cFile ) , NIL ) } ) Return( lWsMethodRet ) /*/ WSMETHOD: AddPsException Autor: Marinaldo de Jesus Data: 05/05/2011 Descricao: Adicionar Tratamento de Excecao no Script em PowerShell /*/ Static Function AddPsException( cPsScript , cCRLF ) Local cPSException := "" Local cMsgException := " 'Não foi possível conectar-se a http://201.48.221.162:2000/ServiceFuturePMS/service?WSDL'" cPSException := "try" cPSException += cCRLF cPSException += "{" cPSException += cCRLF cPSException += cPsScript cPSException += cCRLF cPSException += "}" cPSException += cCRLF cPSException += "catch" cPSException += cCRLF cPSException += "{" cPSException += cCRLF cPSException += cMsgException cPSException += cCRLF cPSException += "}" cPSException += cCRLF Return( cPSException ) $CountUserResult
e o Client gerado a partir dele:
#INCLUDE "PROTHEUS.CH" #INCLUDE "APWEBSRV.CH" /* =============================================================================== WSDL Location http://200.143.193.75:8081/ws/U_FUTUREPMS.apw?WSDL Gerado em 05/05/11 09:58:21 Observações Código-Fonte gerado por ADVPL WSDL Client 1.101007 Alterações neste arquivo podem causar funcionamento incorreto e serão perdidas caso o código-fonte seja gerado novamente. =============================================================================== */ User Function _WHYOFUC ; Return // "dummy" function - Internal Use /* ------------------------------------------------------------------------------- WSDL Service WSU_FUTUREPMS ------------------------------------------------------------------------------- */ WSCLIENT WSU_FUTUREPMS WSMETHOD NEW WSMETHOD INIT WSMETHOD RESET WSMETHOD CLONE WSMETHOD COUNTUSERS WSDATA _URL AS String WSDATA _HEADOUT AS Array of String WSDATA lPSEXCEPTION AS boolean WSDATA nCOUNTUSERSRESULT AS integer ENDWSCLIENT WSMETHOD NEW WSCLIENT WSU_FUTUREPMS ::Init() If !FindFunction("XMLCHILDEX") UserException("O Código-Fonte Client atual requer os executáveis do Protheus Build [7.00.101202A-20110330] ou superior. Atualize o Protheus ou gere o Código-Fonte novamente utilizando o Build atual.") EndIf Return Self WSMETHOD INIT WSCLIENT WSU_FUTUREPMS Return WSMETHOD RESET WSCLIENT WSU_FUTUREPMS ::lPSEXCEPTION := NIL ::nCOUNTUSERSRESULT := NIL ::Init() Return WSMETHOD CLONE WSCLIENT WSU_FUTUREPMS Local oClone := WSU_FUTUREPMS():New() oClone:_URL := ::_URL oClone:lPSEXCEPTION := ::lPSEXCEPTION oClone:nCOUNTUSERSRESULT := ::nCOUNTUSERSRESULT Return oClone // WSDL Method COUNTUSERS of Service WSU_FUTUREPMS WSMETHOD COUNTUSERS WSSEND lPSEXCEPTION WSRECEIVE nCOUNTUSERSRESULT WSCLIENT WSU_FUTUREPMS Local cSoap := "" , oXmlRet BEGIN WSMETHOD cSoap += '' cSoap += WSSoapValue("PSEXCEPTION", ::lPSEXCEPTION, lPSEXCEPTION , "boolean", .T. , .F., 0 , NIL, .T.) cSoap += " " oXmlRet := SvcSoapCall( Self,cSoap,; "http://localhost/u_futurepms.apw/COUNTUSERS",; "DOCUMENT","http://localhost/u_futurepms.apw",,"1.031217",; "http://200.143.193.75:8081/ws/U_FUTUREPMS.apw") ::Init() ::nCOUNTUSERSRESULT := WSAdvValue( oXmlRet,"_COUNTUSERSRESPONSE:_COUNTUSERSRESULT:TEXT","integer",NIL,NIL,NIL,NIL,NIL,NIL) END WSMETHOD oXmlRet := NIL Return .T.
Compile o WSServer, gere o Client baseado na sua URL, teste e me diga se funciona ou não.... Foi um exemplo bem simples. Poderia ter retornado o xml diretamente, mas nesse caso não faria sentido.
Eu testei aqui, e olha o resultado.
NameSpace http://localhost/u_futurepms.apw URL Location http://200.143.193.75:8081/ws/ Nome do Serviço U_FUTUREPMS Método do Serviço COUNTUSERS Resposta da Requisição SOAP1
Bendita WaitRunSrv() e salve o Windows® PowerShell® (a Totvs bem podia contratar o Engenheiro que planejou o novo Shell do Windows® para reescrever a tecnologia Protheus/by you... o que acham ... rs)
Considerações:
1 ) O Pessoal da Tecnologia Protheus deveria rever essa limitação do tamanho da string no protheus;
2 ) AppServer64 já.
Para baixar os códigos utilizados neste "post", cliquem aqui.
[]s
иαldσ dj
(simples assim)
Grande Naldo! Mestre no que faz... Para quem pensou que esse nosso desafio nao daria em nada hein!? hehehehe... é como eu ja disse ate para o Bindo... Marinaldo de Jesus é o cara... o resto...bem... o resto é programador... hehehe
ResponderExcluirÉ isso ae Naldo... vc domina e creio q todos que acompanham devia te-lo como exemplo... analizar... modelar.... desenvolver... Se isso fosse de fato feito, talvez o Protheus nao seria uma colcha de retalho! Grande abraço e obrigado pelo desafio!
Naldo, blz?
ResponderExcluirCara... aproveitando seu tópico... to com um problema aqui... será que você poderia me ajudar?
Seguinte... gerei uma função client de webservice no Protheus que foi compilada certinho... desenvolvi uma função para chamar esse client e blz... tudo funcionava ok.
Porém agora mudaram a URL do webservice e tive que alterar minha função client... pra apontar pra essa nova URL... só que agora, na execução do Protheus, retorna a seguinte mensagem:
"The Web application at http://testehh80.empresaX.com.br/formularios could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application."
Só que o endereço do webservice que configurei na função não é esse... segue o código que escrevi abaixo...
oXmlRet := SvcSoapCall( Self,cSoap,;
"http://tempuri.org/GetCadastrosPendentes",;
"DOCUMENT","http://tempuri.org/",,,;
"http://arasrvvirshp002:85/EmpresaXWsSpMicInt/WsSPMicData.asmx")
O mais engraçado é que essa URL ta funcionando legal no browser do IE e o IDE do Protheus também tá gerando a função desse client certinho.
Enfim... não consegui descobrir o motivo pelo qual o Protheus não chama o webservice do endereço que to passando... e devolve essa mensagem de erro apontando pra esse testehh80.empresaX.
Você pode me ajudar nesse problema?
Obrigado e abraços!
Perguntas-Respostas:
Excluir1) Quando regerou o Client utilizou o mesmo arquivo fonte ou gerou um novo? Já que está apenas atualizado deveria manter o mesmo arquivo fonte limpando-o antes de gerar o novo client.
2) Por via das dúvidas (não que isso seja necessário) você excluiu do Projeto e, consequentemente, do RPO o código do Client antigo antes da geração do novo?
Com as informações passadas, as perguntas-respostas acima talvez resolvam o seu "problema". Caso contrário necessitarei de mais informações.
Uma forma de descobrir se, de fato o seu RPO está compilado com a última versão é verificando via "Object Inspector" ou utilizando-se das funções existentes no post:
Protheus :: Advpl :: Usando GetFuncArray, GetApoInfo e VarInfo ( http://goo.gl/k9Fea ).
Se os itens acima elencados não solucionarem o seu problema envie-me o código do client (o novo) e o seu RPO para mail@blacktdn.com.br. Dessa forma poderei comparar ambos os códigos.
TryExeption.ch? Onde consigo essa CH? rsrs
ResponderExcluir