Usługa WCF dławi się na właściwościach bez „zestawu”. Jakieś obejście?


97

Mam pewną klasę, którą mijam w wyniku metody usługi i ta klasa ma właściwość tylko do pobierania:

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

Otrzymuję wyjątek po stronie usług:

System.Runtime.Serialization.InvalidDataContractException: Nie ustawiono metody dla właściwości „Message” w typie „MyNamespace.ErrorBase”.

Muszę mieć tę właściwość jako jedyny getter, nie mogę pozwolić użytkownikom na przypisywanie jej wartości. Jakieś obejście, którego mógłbym użyć? A może brakuje mi jakiegoś dodatkowego atrybutu?

Odpowiedzi:


107

Podaj Message publiczny pobierający, ale chroniony ustawiający, aby tylko podklasy (i DataContractSerializer, ponieważ oszukuje :) mogą modyfikować wartość.


To zgrabne rozwiązanie!
Russell

Dzięki, cieszę się, że to było przydatne! W rzeczywistości jest to tylko jedno z kilku zastosowań tej sztuczki. Ponieważ metody pobierające i ustawiające są technicznie funkcjami, możesz również użyć tej samej techniki, aby zapewnić niestandardową serializację typów pierwotnych (być może niestandardowego formatu czasu w XML) bez konieczności używania onieśmielającego IDataContractSurrogate.
rh.

28
Możesz nawet uczynić to prywatnym. Serializer nie ma nic przeciwko temu, czy jest prywatny, publiczny, chroniony, wewnętrzny czy chroniony wewnętrznie.
Abel

8
i stwórz seterathrow new NotSupportedException()
Simon_Weaver

2
Posiadanie private set;działa, jeśli używasz [DataContract]i [DataMember]. Jeśli je pominiesz, potrzebujesz public set;.
user276648

12

Nawet jeśli nie musisz aktualizować wartości, funkcja ustawiająca jest używana przez WCFSerializer do deserializacji obiektu (i ponownego ustawiania wartości).

To SO jest tym, czego szukasz: WCF DataContracts


1
Więc jedynym sposobem na przezwyciężenie tego problemu jest uczynienie z tego metody zamiast własności? Ponownie, nie mogę zezwolić na „ustawienie” w tej nieruchomości
Andrey,

Możesz uczynić z tego metodę (np. GetMessage () {return ";}) alternatywnie, jestem prawie pewien, że możesz powiedzieć Serializerowi WCF, aby to zignorował. Zobaczę, co uda mi się znaleźć, i dam znać.
Russell,

1
To pytanie o stackoverflow trafia w sedno: stackoverflow.com/questions/172681/wcf-datacontracts
Russell,

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

5

Jeśli masz tylko metodę pobierającą, dlaczego w ogóle musisz serializować właściwość. Wygląda na to, że można usunąć atrybut DataMember dla właściwości tylko do odczytu, a serializator po prostu zignoruje tę właściwość.


3
W rzeczywistości nie ma sensu serializowanie właściwości pochodnej (np. Właściwości adresu URL, która jest obliczana z właściwości ID) do trwałego magazynu (np. Bazy danych) - głosuj za tym - ale ma sens serializować ją do reprezentacja (np. JSON lub XML) zwracana przez żądanie API.
Florian Winter

4

Nie mógłbyś mieć po prostu ustawiacza „nic nie rób”?

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

Czy też barf serializatora DataContract również?


14
Nie działa, po prostu nie chciałem pozwolić programistom używającym API klienta myśleć, że mogą przypisać rzeczy do nieruchomości.
Andrey

2

Właściwości z atrybutem DataMember zawsze wymagają ustawienia. Powinieneś ponownie napisać podobny obiekt w aplikacji klienckiej, ponieważ członkom DataContract zawsze można przypisać wartości.


2

Miałem ten problem z ASP.NET MVC i chciałem używać DataContractSerializer, aby móc kontrolować nazwy elementów w danych wyjściowych JSON. Ostatecznie przełączyłem serializator na JSON.NET, który obsługuje właściwości bez metod ustawiających (których DataContractSerializer nie obsługuje) i kontrolę nazwy właściwości (której wbudowany serializator JSON w ASP.NET MVC nie obsługuje) za pośrednictwem [JsonProperty(PropertyName = "myName")].


2

Jeśli jest to realna opcja, zamiast mieć ErrorBasejako klasę bazową, zdefiniuj ją w następujący sposób:

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

            // leave unattributed
            set;
        }
    }

Teraz, mimo że setter istnieje, jest niedostępny dla klienta za pośrednictwem kanału WCF, więc jest tak, jakby był prywatny.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.