WCF se ahoga en propiedades sin "conjunto". ¿Alguna solución?

97

Tengo una clase que estoy pasando como resultado de un método de servicio, y esa clase tiene una propiedad de solo obtención:

[DataContract]
public class ErrorBase
{
  [DataMember]
  public virtual string Message { get { return ""; } }
}

Recibo una excepción en el lado del servicio:

System.Runtime.Serialization.InvalidDataContractException: ningún método establecido para la propiedad 'Mensaje' en el tipo 'MyNamespace.ErrorBase'.

Tengo que tener esta propiedad como único captador, no puedo permitir que los usuarios le asignen un valor. ¿Alguna solución alternativa que pueda utilizar? ¿O me falta algún atributo adicional?

Andrey
fuente

Respuestas:

106

Dale a Message un captador público pero configurador protegido, de modo que solo las subclases (y el DataContractSerializer, porque hace trampa :) puedan modificar el valor.

rh.
fuente
¡Esa es una buena solución!
Russell
Gracias, me alegro de que haya sido útil. En realidad, este es solo uno de los varios usos de este truco. Dado que los captadores y definidores son técnicamente funciones, también puede utilizar esta misma técnica para proporcionar una serialización personalizada de tipos primitivos (quizás un formato de tiempo personalizado en XML) sin necesidad de manejar el intimidante IDataContractSurrogate.
rh.
28
Incluso podrías hacerlo privado. Al serializador no le importa si es privado, público, protegido, interno o interno protegido.
Abel
8
y hacer el setterthrow new NotSupportedException()
Simon_Weaver
2
Tener un private set;funciona si usa [DataContract]y [DataMember]. Si los omite, necesita public set;.
user276648
12

Incluso si no necesita actualizar el valor, WCFSerializer usa el setter para deserializar el objeto (y restablecer el valor).

Esto es lo que busca : WCF DataContracts

Russell
fuente
1
Entonces, ¿la única forma de superar el problema es convertirlo en un método en lugar de una propiedad? Una vez más, no puedo permitir "establecer" en esta propiedad
Andrey
Podría convertirlo en un método (por ejemplo, GetMessage () {return "";}) alternativamente, estoy bastante seguro de que podría decirle al serializador WCF que lo ignore. Veré lo que puedo encontrar y te lo haré saber.,
Russell
1
Esta pregunta de stackoverflow da en el clavo: stackoverflow.com/questions/172681/wcf-datacontracts
Russell
11
[DataMember(Name = "PropertyName")]
public string PropertyName
{
    get
    {
        return "";
    }
    private set
    { }
}
Rikin Patel
fuente
5

Si solo tiene un captador, ¿por qué necesita serializar la propiedad? Parece que podría eliminar el atributo DataMember para la propiedad de solo lectura, y el serializador simplemente ignoraría la propiedad.

Rob Lambert
fuente
3
De hecho, no tiene sentido serializar una propiedad derivada (p. Ej., Una propiedad de URL que se calcula a partir de una propiedad de ID) en un almacenamiento persistente (p. Ej., Una base de datos) - voto positivo para eso - pero tiene sentido serializarlo en un representación (por ejemplo, JSON o XML) que se devuelve mediante una solicitud de API.
Florian Winter
3

¿No podrías tener un armador de "no hacer nada"?

[DataContract]
public class ErrorBase
{
  [DataMember]
  public virtual string Message 
  {
      get { return ""; } 
      set { }
  }
}

¿O el serializador de DataContract también lo hace?

marc_s
fuente
14
No vomita, simplemente no quería que los desarrolladores que usaban la API del cliente pensaran que pueden asignar cosas a la propiedad.
Andrey
2

Las propiedades con el atributo DataMember siempre requieren un conjunto. Debe volver a escribir un objeto similar en la aplicación cliente, ya que a los miembros de DataContract siempre se les pueden asignar valores.

Jojo Sardez
fuente
2

Tuve este problema con ASP.NET MVC y yo quería usar DataContractSerializer para poder controlar los nombres de los elementos en la salida JSON. Finalmente, cambié el serializador a JSON.NET, que admite propiedades sin establecedores (que DataContractSerializer no lo hace) y control de nombre de propiedad (que el serializador JSON incorporado en ASP.NET MVC no) a través de [JsonProperty(PropertyName = "myName")].

Thomas Lundström
fuente
2

Si es una opción viable, en lugar de tenerla ErrorBasecomo clase base, defínala de la siguiente manera:

    public interface IError
    {
        string Message
        {
            [OperationContract]
            get;

            // leave unattributed
            set;
        }
    }

Ahora, aunque existe un establecedor, es inaccesible para el cliente a través del canal WCF, por lo que es como si fuera privado.

Gilad
fuente