WCF soffoca sulle proprietà senza "set". Qualche soluzione alternativa?


97

Ho una classe che sto passando come risultato di un metodo di servizio e quella classe ha una proprietà get-only:

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

Ricevo un'eccezione dal lato del servizio:

System.Runtime.Serialization.InvalidDataContractException: nessun metodo impostato per la proprietà "Message" nel tipo "MyNamespace.ErrorBase".

Devo avere questa proprietà come unico getter, non posso consentire agli utenti di assegnarle un valore. Qualche soluzione alternativa che potrei usare? O mi manca qualche attributo aggiuntivo?

Risposte:


106

Dai a Message un getter pubblico ma un setter protetto, in modo che solo le sottoclassi (e il DataContractSerializer, perché imbroglia :) possano modificare il valore.


Questa è una bella soluzione!
Russell

Grazie, contento che sia stato utile! Questo in realtà è solo uno dei tanti usi di questo trucco. Poiché getter e setter sono tecnicamente funzioni, è anche possibile utilizzare questa stessa tecnica per fornire la serializzazione personalizzata di tipi primitivi (forse un formato orario personalizzato in XML) senza la necessità di brandire il intimidatorio IDataContractSurrogate.
rh.

28
Potresti anche renderlo privato. Il serializzatore non si preoccupa se è privato, pubblico, protetto, interno o interno protetto.
Abel

8
e fai il setterthrow new NotSupportedException()
Simon_Weaver

2
Avere un private set;lavoro se usi [DataContract]e [DataMember]. Se li ometti, hai bisogno di public set;.
user276648

12

Anche se non è necessario aggiornare il valore, il setter viene utilizzato da WCFSerializer per deserializzare l'oggetto (e reimpostare il valore).

Questo è ciò che stai cercando : WCF DataContracts


1
Quindi l'unico modo per me di superare il problema è renderlo un metodo invece che una proprietà? Ancora una volta, non posso consentire "set" su questa proprietà
Andrey

Potresti renderlo un metodo (es. GetMessage () {return "";}) in alternativa, sono abbastanza sicuro che potresti dire al serializzatore WCF di ignorarlo. Vedrò cosa riesco a trovare e ti farò sapere.,
Russell

1
Questa domanda su stackoverflow colpisce nel segno: stackoverflow.com/questions/172681/wcf-datacontracts
Russell

11
[DataMember(Name = "PropertyName")]
public string PropertyName
{
    get
    {
        return "";
    }
    private set
    { }
}

5

Se hai solo un getter, perché devi serializzare la proprietà? Sembra che tu possa rimuovere l'attributo DataMember per la proprietà di sola lettura e il serializzatore ignorerebbe semplicemente la proprietà.


3
Non ha davvero senso serializzare una proprietà derivata (ad esempio, una proprietà URL che viene calcolata da una proprietà ID) in una memoria persistente (ad esempio, un database) - upvote per questo - ma ha senso serializzarla in un rappresentazione (ad esempio, JSON o XML) restituita da una richiesta API.
Florian Winter

3

Non potresti semplicemente avere un setter "non fare nulla" ??

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

O anche il serializzatore DataContract barf?


14
Non sbuffa, semplicemente non volevo che gli sviluppatori che utilizzano l'API client pensassero di poter assegnare cose alla proprietà.
Andrey

2

Le proprietà con l'attributo DataMember richiedono sempre set. È necessario riscrivere oggetti simili sull'applicazione client poiché ai membri DataContract possono sempre essere assegnati valori.


2

Ho avuto questo problema con ASP.NET MVC e volevo utilizzare DataContractSerializer per poter controllare i nomi sugli elementi nell'output JSON. Alla fine sono passato al serializzatore JSON.NET, che supporta le proprietà senza setter (che DataContractSerializer non fa) e il controllo del nome della proprietà (che il serializzatore JSON integrato in ASP.NET MVC non lo fa) tramite [JsonProperty(PropertyName = "myName")].


2

Se è un'opzione praticabile, invece di averla ErrorBasecome classe base, definiscila come segue:

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

            // leave unattributed
            set;
        }
    }

Ora, anche se esiste un setter, è inaccessibile al client tramite il canale WCF, quindi è come se fosse privato.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.