jueves, enero 28, 2010

Consumiendo desde .Net un Web Service publicado en Java (HttpWebRequest da time out)

Tomado de:

http://snoopdotnet.wordpress.com/2010/01/28/consumiendo-desde-net-un-web-service-publicado-en-java-httpwebrequest-da-time-out/

Consumiendo desde .Net un Web Service publicado en Java (HttpWebRequest da time out) January 28, 2010
Posted by Leandro Romero in .NET, Arquitectura, Diseño, Tips, coding.
Tags: GetRequestStream Time Out, java, troubleshooting, web service
trackback

Buenas gente! Tanto tiempo!

Desde hace un tiempo estoy trabajando en un aplicación que consume unos web services hechos en Java, la cual por momentos tiene bastante concurrencia y operaciones que demandan mucho trabajo para las dos “puntas” que están en juego.

Tengo que aclarar que esta aplicación no la desarrollé yo, la “heredé” digamos. Así que lo que estaba en producción andaba sin problemas. Los usuarios se conectaban, hacían sus operaciones sin mayores problemas, y como no necesitaba mayores mantenimientos esa parte yo no la había tenido demasiado en cuenta.

Hasta que llegó el día que el servicio que exponía el amigo (nótese: AMIGO) java tuvo que sufrir algunos cambios, con lo cual tuve que actualizar referencias del Wsdl en mi solución .Net. Hasta acá nada del otro mundo, agarro el proyecto donde está la referencia Web (sí, está hecho a la antigua porque la aplicación es del 2006) pego la nueva dirección del wsdl y actualizo referencias. Esto hace que la clase que hace de proxy se regenere (básicamente borra lo que estaba y vuelve a armar los archivos necesarios, entre ellos el Reference.cs). Compilo, genero el exe nuevo y le digo al analista: “Deployalo en preproducción para acelerar la salida a producción, total no toqué nada, debería andar como hasta ahora”

Y no, por algo existe Murphy. A los dos días el cliente que estaba haciendo las pruebas en prepro me dice: “Lean, esto que compilaste no anda”. “Cómo que no anda si no toqué nada??!?!” (La excusa del programador nº 1) “No anda, tira un error de conección cuando se conectan 3 usuarios y ejecutan una tarea los 3, fijate el log!”

Y como buen desarrollador profesional que soy, fuí a ver el log y decía:

The operation has timed out System.Net.WebException System.IO.Stream GetRequestStream() at System.Net.HttpWebRequest.GetRequestStream() at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)

“Elemental mi querido Watson” dije al ver el time out, “el server java no está respondiendo”, pero no, la excepción es bastante clara, está fallando al obtener el Request Stream; o sea, no mandó nada todavía, se está preparando para hacer la llamada y falla. Raro, no?

Investigando esa excepción (googleando) en los foros todos eran bastante claros “Flaco, a los stream que abras cerralos, eso te pasa por no cerrarlos: Stream.Close() papá!” (son foros argentinos, por eso) Pero no, yo no me encargo de streams ni nada de eso a mano, porque para eso está el código generado automáticamente por el Visual Studio y este código es el mejor, no tiene errores, es perfecto porque lo hace automático el Visual Studio no?

NO, claramente es la Lección aprendida 1. Según este blog (el único que vi que dió con este problema) que me pasó mi buen amigo Charly es un bug del proxy que se genera automáticamente, para solucionar esto hay que deshabilitar el parámetro KeepAlive del request, más específicamente hacer un override de un método de esa clase y deshabilitarlo y más técnicamente hablando:

protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
HttpWebRequest webRequest = (HttpWebRequest)base.GetWebRequest(uri);
webRequest.KeepAlive = false;
webRequest.ConnectionGroupName = Guid.NewGuid().ToString();
return webRequest;
}

Puse esto en la clase proxy (la que está en el archivo Reference.cs) y voilà! problema arreglado :)

Ahora, haciendo un poco de reflexión, por qué antes andaba y cuando yo regeneré el cliente tuve que hacer esto??? Para despejar esta duda que no me dejaba dormir, utilicé una herramienta amiga llamada Reflector para ver el código de la dll que se compiló en su momento, ya que dudaba de los fuentes que había heredado y sí, efectivamente estaba esa porción de código de alguien (sólo Dios sabe quien) que se topó con el mismo problema.

Leccion aprendida 2 (y consejo sano, además). Siempre documentar las soluciones “mágicas” que se incluyan en el código, porque uno nunca sabe quién va a ser el pobre santo (o gil) que lo herede y más si se escriben en archivos que se generan automáticamente.

Y ahora sí, el cliente lo probó en test, lo deployamos en preproducción donde fue sometido a estrés sin ningún problema y finalmente salió a producción. Siempre son lindos los finales felices!

Gracias Leandro.

No hay comentarios: