Fantasmas en el código | De WebClient, Silverlight, UserAgents, WebApi y “gatitos que mueren”

posterEste no es un artículo de los que tengo acostumbrado escribir, este artículo es una reflexión-desahogo en la que busco opiniones y consejos de aquellos que tengan los conocimientos y/o las ganas de ilustrarme/nos sobre uno de esos fantasmas con los que me he encontrado a lo largo de mi carrera.

Bueno, al lío. Todo comenzó con la necesidad de usar Silverlight, sí, esa tecnología que parece destinada a quedar en desuso, en una aplicación web ASP.NET MVC y consumiendo datos desde un proyecto WebApi. Hasta aquí toda la mezcla puede parecer normal, ejecuto la aplicación ASP.NET MVC, accedo a la vista con el control Silverlight y… ¡todo correcto! El control muestra todos los datos correctamente y la aplicación funciona perfectamente… ¿o no?

Todo desarrollador web sabe que antes de dar por concluido el desarrollo de una aplicación debe probarla en todos los navegadores y… no señores, esta vez no es IE. En este caso es Firefox el que nos da problemas. ¡Vaya por diox! Resulta que en el navegador del zorrillo, no se me muestran datos porque la respuesta a la petición que he hecho con WebClient retorna un error porque estoy esperando un JSON y resulta que me llega un XML. Surge la pregunta de Mourinho… ¿Por qué?

Una vez puesto el mono de trabajo, abro Fiddler y veo que el parámetro de cabecera “Accept” que se envía desde Firefox es este churrasco que intenta primero obtener HTML, después xhtml, en tercer lugar XML y por último que acepte lo que venga.

image

 

Veamos qué en Chrome ni siquiera se establece ese parámetro.

image

 

Y finalmente IE que establece */*, o lo que es lo mismo, acepta todo.

image

 

Primer intento de solución

Mi primera intención fue forzar el parámetro Accept a */* pero tras ver que no tengo el método “Add” para la colección “Headers” indago un poco y encuentro que para Silverlight se establecen una serie de restricciones de los parámetros de la cabecera y que no podemos modificarlos, entre ellos “Accept” tal y como se especifica en la sección “Comentarios” de este artículo de MSDN.

Y digo yo… pero ¿y qué más da el navegador? Pues bien, resulta que la documentación de Silverlight indica que se establece por el navegador que contiene la aplicación de Silverlight, he aquí el artículo de MSDN que lo explica.

 

Segundo intento de solución

Usar HttpWebRequest pero sólo obtuve los mismos resultados y problemas.

 

Solución rápida (sólo para mi)

Podemos cambiar la configuración de Firefox para que el parámetro “Accept” admita antes JSON que XML tal y como se indica en este artículo pero… esto sólo me vale para mi, si la aplicación la va a usar más de… una persona (yo mismo) ya no mola.

Entonces… ¿qué hacer?

 

Solución aplicada

Una vez me cansé de intentar buscar la forma de establecer desde la aplicación cliente el formato en el que quería recibir los datos (JSON), pensé que puedo ir a WebApi y establecer/forzar que me envíe los datos sólo en el formato que quiero.

NOTA: No me gusta nada esta solución porque pierdo la flexibilidad de WebApi. ¿Y si mañana quiero los datos también en XML?

Gracias a la ayuda de un compañero, encontré que podía forzarlo añadiendo una única línea en el método Application_Start del Global.asax del proyecto WebApi

GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

 

La misma solución parece un poco más elegante haciéndolo como se indica en este post de StackOverflow pero es más de lo mismo.

 

La mejor aproximación a la solución es la que se comenta en este artículo que he encontrado pero volvemos a reducirlo a lo mismo.

 

Vuestra recomendación

Como ya dije al inicio del artículo, espero vuestras recomendaciones, indicaciones y/o palos diciendo ¡eres un inútil! ¡eso no se hace así! ¿Quién es el primero?

 

Enjoy y recuerda que “cada vez que aparece un fantasma en el código, muere un gatito”

6 Comentarios

  1. adiazmartin

    ¿y si usas HTML5 en vez de Silverlight? 😀

  2. pedrohurtado

    Buenas,

    La verdad que mas que “gatitos que muerden”. Yo pondría “mana de despropósitos” Y voy a ver si me explico.

    El primero es utilizar Silverlight, en esto creo que estamos todos de acuerdo:) Y no precisamente porque no tenga continuidad sino porque siempre ha sido una cagada…

    El segundo es utilizar WebClient y todos sus sucedáneos y me explico.

    Parece que el problema es FireFox cuando no lo es, sino el utilizar WebClient y esas cosas que suele inventar Micro para ahorrarnos trabajo y que no hacen más que convertirnos en zombies en el mundo web.

    Si a eso le sumo que la documentación es mala, pues pasa lo que te ha pasado a ti que por simplificar y por hacer las cosas fáciles(que yo creo que difíciles) entramos en perder un montón de horas por culpa de no escribir 4 lineas que además están presentes desde creo que la versión 1 del framework.

    Olvidate de WebClient y utilizalo solo para las demos que mira como sin tocar y sin hacer nada de nada y sin que sea culpa de los browser se puede modificar el “accept”.

    public partial class MainPage : UserControl
    {
    public MainPage()
    {
    WebRequest.RegisterPrefix(“http://”,
    System.Net.Browser.WebRequestCreator.BrowserHttp);
    WebRequest.RegisterPrefix(“https://”,
    System.Net.Browser.WebRequestCreator.BrowserHttp);
    InitializeComponent();
    GetData();
    }
    private void GetData()
    {
    Uri apiUri = new Uri(Application.Current.Host.Source, “/api/TableCounts/”);

    //Make the request
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(apiUri);
    request.Accept = “application/json”;
    request.BeginGetResponse(new AsyncCallback(ProcessData), request);
    }
    private void ProcessData(IAsyncResult ar)
    {
    HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar);

    using (StreamReader sr = new StreamReader(response.GetResponseStream(),
    System.Text.Encoding.UTF8))
    {
    //Resto de código

    }
    }
    }

    No se ni porque he abierto para probar yo un proyecto Silverlight, voy a lavarme las manos y quitarme los microbios xDDDD.

  3. santypr

    @Alberto lo suyo sería usar HTML5 pero… no se puede porque el control Silverlight es un Pivot Viewer que… hasta donde sé no existe en HTML5 (lo podemos hacer jejeje)

  4. santypr

    @Pedro voy a probar este código :o)

  5. pedrohurtado

    Que vas a probar, que ya te he dicho que me he contaminado xDDDD. Te falto leer esta parte de la documentación

    http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.accept(v=vs.95).aspx

    En vez de esta otra que expones en el post

    http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.headers(v=vs.95).aspx

  6. santypr

    @Pedro sí la leí. El problema es en Silverlight que “Access” no es accesible en WebClient http://msdn.microsoft.com/es-es/library/system.net.webheadercollection(v=vs.110).aspx
    Para HttpWebRequest me retornaba error a la hora de realizar la llamada :o(

Leave a Reply

Tema creado por Anders Norén