[WCF] Vuelta a la realidad,… y jugando con el DataContractSerializer

Hola a todos!!!!, han pasado muchas semanas sin que haya actualizado el blog, de hecho ni me he acercado a él. Necesitaba desconectar y vaya que si lo he hecho… :). Pero todo se acaba, así que aquí vuelvo a soltar rollazos a troche y moche (tampoco muchos, que esto de escribir cansa…).

 

Uno de mis mayores problemas que he encontrado cuando se trabaja con un patrón proxy (como Remoting, WCF,…) es que mucha gente no tiene claro dónde van sus objetos y cómo se pasan los valores por referencia, por valor, etc… Y se escucha mucho eso de…”He pasado mi clase loquesea y cuando actualizo en el servidor su valor, no me lo devuelve cambiado…”

 

Debo deciros que a mí también me costó lo suyo (uno que es lento…), pero bueno es bastante normal que esto ocurra, y también es normal que haya formas de evitar esto, por ejemplo en Remoting había que poner explícitamente el “ref” en la variable y el se encargaba de mantener el cambio y devolverlo.

 

Pues estuve buscando algo similar para utilizar en WCF, y encontré que si usamos el DataContractSerializer (el serializador que se usa por defecto en WCF), tenemos una opción parecida aunque un poco más compleja de elaborar, se hace a través de OperationBehavior y decoradores de métodos.

 

Generamos un DataContractSerializerOperationBehavior

Creamos una clase que herede de “DataContractSerializarOperationBehavior”, este es el behavior que luego aplicaremos a través del decorador.

public class SerializadorConReferencias : DataContractSerializerOperationBehavior
{
public SerializadorConReferencias(OperationDescription operationDescription)
: base(operationDescription)
{ }

public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return CreateDataContractSerializer(type, name, ns, knownTypes);
}

private static XmlObjectSerializer CreateDataContractSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return CreateDataContractSerializer(type, name, ns, knownTypes);
}

public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
2147483647 /* En plan bruto... */,
this.IgnoreExtensionDataObject,
true /*Aquí esta el cambio*/,
this.DataContractSurrogate);
}
}

 

El caso está en el último CreateSerializer al que ponemos a true la propiedad de “PreserveReferences”. Usando este serializador en vez del de por defecto ya lo tendríamos, pero queda más elegante si usamos un decorador de métodos y así decidimos los métodos que queremos que lo usen y los que no.

 

Generamos un decorador que extienda IOperationBehavior

Para crear un decorador debemos heredar de Attribute y además en este caso debemos implementar el interfaz IOperationBehavior para poder aplicar este behavior en la operación (Método) que deseemos.

public class ConReferenciasDec : Attribute, IOperationBehavior
{
#region IOperationBehavior Members
public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}

public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
IOperationBehavior innerBehavior = new SerializadorConReferencias(description);
innerBehavior.ApplyClientBehavior(description, proxy);
}

public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
{
IOperationBehavior innerBehavior = new SerializadorConReferencias(description);
innerBehavior.ApplyDispatchBehavior(description, dispatch);
}

public void Validate(OperationDescription description)
{
}

#endregion

}

Aquí lo único a destacar es que tenemos que aplicar el behavior en el cliente y en el servidor. Ahora sólo nos quedaría utilizarlo.

public interface IService
{

[OperationContract]
[ConReferenciaDec]
void DoSomething(ComplexType algo);
}

 

Conclusiones

WCF mola mucho y se pueden hacer muchísimas cosas de una forma más o menos sencilla. En este caso en particular yo no estoy muy de acuerdo en utilizar este tipo de cosas, intento explicarme, tengo claro que la forma habitual de trabajar en .NET es que si pasas un tipo complejo a un método este siempre lo pasa por referencia, esto es cierto siempre y cuando ocupen el mismo espacio de memoria, que en el caso que nos ocupa NUNCA ocurre, porque para eso estamos a través de un proxy. Es preferible que tú método devuelva el mismo tipo y te lo pase cambiado y que los desarrolladores tengan muy clara la diferencia.

Aunque bueno para gustos los colores así que cada uno tendrá su opinión.

 

Hasta la próxima…

Mario Ropero…a medio gas…

2 comentarios en “[WCF] Vuelta a la realidad,… y jugando con el DataContractSerializer”

  1. Joder mario, esta bien el ejemplo pero estaría mejor no reinventar la rueda :-). Para eso los DataContract ya tiene una propiedad llamada IsReference que si la pones a true ya tienes el parametro preserveObjectReferences a true. Claro está esto solamente en WCF 3.5 SP1 .. ¿¿averiguas el principal motivo para hacerlo ?? Es decir, para dar soporte a que lo han introducido??

  2. Buenas Unai, la verdad es que no investigué sobre los DataContract con el nuevo SP1, imagino que lo introducirán como mejoras para tú querido EF 🙂

    Un saludín.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *