Servicios web JSON en .NET y cómo evitar el parámetro d con un filtro

Si hemos creado un servicio web en .NET que devuelve los resultados en formato JSON (más o menos como comentábamos en este artículo) y utilizamos la versión 3.5 o superior del Framework, puede que nos ocasione algún problema el parámetro «d», que .NET introduce automáticamente en la respuesta para evitar una vulnerabilidad (de la que hablábamos en este otro artículo).
En mi caso, al migrar un proyecto de .NET 2.0 a .NET 4.0, muchas aplicaciones que utilizaban los servicios web basados en JSON dejaron de funcionar, ya que no esperaban encontrarse el parámetro «d» en la respuesta.
Si estáis en la misma situación, y la mencionada vulnerabilidad no os afecta o preocupa, podéis solucionarlo creando un filtro para eliminar el parámetro. A continuación incluyo mi clase StreamFilter:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;

namespace MiNamespace {
  public class StreamFilter : System.IO.Stream {
    private Stream Base;
    private MemoryStream Ms;

    public StreamFilter(Stream ResponseStream) {
      if (ResponseStream == null) {
        throw new ArgumentNullException("ResponseStream");
      }
      Base = ResponseStream;
      Ms = new MemoryStream();
    }
  
    public override bool CanRead {
      get { return Base.CanRead; }
    }
    public override bool CanSeek {
      get { return Base.CanSeek; }
    }
    public override bool CanWrite {
      get { return Base.CanWrite; }
    }
    public override void Flush() {
      Base.Flush();
    }
    public override long Length {
      get { return Base.Length; }
    }
    public override long Position {
      get { return Base.Position; }
      set { Base.Position = value; }
    }

    public override int Read(byte[] buffer, int offset, int count) {
      return this.Base.Read(buffer, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin) {
      return Base.Seek(offset, origin);
    }

    public override void SetLength(long value) {
      Base.SetLength(value);
    }

    public override void Write(byte[] buffer, int offset, int count) {
      Ms.Write(buffer, offset, count);
    }

    public override void Close() {
      string html = System.Text.Encoding.UTF8.GetString(Ms.ToArray());
      if (html.StartsWith("{\"d\":")) {
        html = html.Substring("{\"d\":".Length);
      }
      html = html.TrimEnd();
      if (html.EndsWith("}}")) {
        html = html.Substring(0, html.Length - 1);
      }
      byte[] buffer = System.Text.Encoding.UTF8.GetBytes(html);
      this.Base.Write(buffer, 0, buffer.Length);
      base.Close();
      this.Base.Close();
    }
  }
}
Como se puede ver, el filtro únicamente elimina el parámetro «d» que encapsula a los resultados sobreescribiendo el método Close de la clase Stream.
Para utilizar el filtro, sólo tenemos que incluir las siguientes líneas en el método Application_BeginRequest del fichero Global.asax:
protected void Application_BeginRequest(object sender, EventArgs e) {
  if (Request.ContentType.ToLower().Contains("application/json")) {
    Response.Filter = new MiNamespace.StreamFilter(Response.Filter);
  }
}

Como seguramente no necesitamos  el filtro en todas las peticiones de nuestro sitio web, lo añadimos únicamente cuando el content-type de la petición es «application/json«.

Nuestra puntuación
Twittear
Compartir
Compartir
Pin