ServiceContract
Definiuje funkcjonalność wystawioną przez serwis WCF. Dobrą praktyką jest oznaczanie tym atrybutem interfejsu .NET tak, aby zapewnić pewną warstwę abstrakcji nad konkretnymi implementacjami. Przykładowo:
[ServiceContract] public interface IEvaluationService { [OperationContract(IsOneWay = true)] void SubmitEvaluation(Evaluation eval); [OperationContract] List<Evaluation> GetEvaluations(); }
Property IsOneWay oznacza, że dana operacja nie zwraca wyniku. Konkretną implementację interfejsu można konfigurować poprzez atrybut ServiceBehavior.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)] public class EvaluationService : IEvaluationService { private List<Evaluation> _evals = new List<Evaluation>(); public void SubmitEvaluation(Evaluation eval) { _evals.Add(eval); } public List<Evaluation> GetEvaluations() { return _evals; } }
InstanceContextMode: Single - Singleton, PerCall - zawsze nowa instancje, Session - każdy klient dostaje unikalną instancje w obrębie sesji.
ConcurrencyMode - Single - tylko jeden wątek ma dostęp do obiektu, Multiple - dostępny dla wielu wątków, Reentrant - nowe operacje mogą być wykonywane tylko podczas wywoływania innego serwisu.
DataContract
Definiuje typy, które mają być serializowane i przesyłane dalej przez WCF. Domyślny serializator to DataContractSerializer, który sprawdza, które obiekty są oznaczone tym atrybutem. Serializowane będą te propercje lub pola, które są oznaczone atrybutami DataMember.
[DataContract] public class Evaluation { [DataMember(IsRequired = true)] public string Submitted { get; set; } [DataMember(Order = 2)] public DateTime TimeSent { get; set; } [DataMember] public string Comments { get; set; } }
Jeżeli w odebranej wiadomości nie będzie wartości, którą możnaby zdeserializować na property oznaczone z opcją IsRequired, aplikacja zwróci błąd. Poprzez opcję Order możemy ustawiać kolejność elementów w XML-u.
Problem może pojawić się w sytuacji, gdy chcemy wykorzystać mechanizm polimorfizmu. Jeżeli w sygnaturach metod mamy klasy bazowe, natomiast chcemy zwrócić klasę po nich dziedziczącą musimy użyć atrybutu KnownType. Znane typy dziedziczące po klasie bazowej zostaną dodane do kontraktu..
[DataContract] [KnownType(typeof(Car))] public abstract class Vehicle { [DataMember] public string Name { get; set; } } [DataContract] public class Car : Vehicle { [DataMember] public int Year { get; set; } }
MessageContract
Pozwala na zdefiniowanie, które pola mają znajdować się w nagłówku SOAP, a które w body. Typ oznaczony typ atrybutem przekazujemy do metody oznaczonej atrybutem OperationContract.
[DataContract] public class Evaluation { [DataMember(IsRequired = true)] public string Submitted { get; set; } [DataMember(Order = 2)] public DateTime TimeSent { get; set; } [DataMember] public string Comments { get; set; } } [DataContract] public class CustomHeader { [DataMember] public string Username { get; set; } } [MessageContract] public class EvaluationRequest { [MessageHeader] public CustomHeader EvaluationHeader { get; set; } [MessageBodyMember] public Evaluation EvaluationBody { get; set; } }
Dzięki temu wiadomość SOAP przyjmuje poniższą postać:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope"> <s:Header> <a:Action s:mustUnderstand="1">http://tempuri.org/IEvaluationService/SubmitEvaluation</a:Action> <h:EvaluationHeader xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://tempuri.org/"> <Username xmlns="http://schemas.datacontract.org/2004/07/EvaluationServiceLibrary">Joe</Username> </h:EvaluationHeader> </s:Header> <s:Body> <EvaluationRequest xmlns="http://tempuri.org/"> <EvaluationBody xmlns:d4p1="http://schemas.datacontract.org/2004/07/EvaluationServiceLibrary" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <d4p1:Comments>Git</d4p1:Comments> <d4p1:Submitted>Yes</d4p1:Submitted> <d4p1:TimeSent>2013-10-27T12:46:00</d4p1:TimeSent> </EvaluationBody> </EvaluationRequest> </s:Body> </s:Envelope>
Brak komentarzy:
Prześlij komentarz