Wygląda na to, że próbujesz użyć architektury SOA, aby uzyskać zdalny dostęp do modelu obiektu. Lepiej byłoby przyjrzeć się interakcjom i możliwościom, które ma ujawnić Twoja usługa, i unikać ujawniania szczegółów dotyczących dziedziczenia realizacji usług.
Więc w tym przypadku, gdzie trzeba listę kont użytkowników twój interfejs będzie wyglądać następująco
[ServiceContract]
interface ISomeService
{
[OperationContract]
Collection<AccountSummary> ListAccountsForUser(
User user /*This information could be out of band in a claim*/);
}
[DataContract]
class AccountSummary
{
[DataMember]
public string AccountNumber {get;set;}
[DataMember]
public string AccountType {get;set;}
//Other account summary information
}
jeśli zdecydujesz się pójść w dół trasą dziedziczenia, można użyć KnownType attribute, ale należy pamiętać, że spowoduje to dodanie pewnych informacji o typie do wiadomości przesyłanej przez kabel, co może w niektórych przypadkach ograniczyć interoperacyjność.
Aktualizacja:
byłem nieco ograniczony do czasu wcześniejszego, kiedy odpowiedział, więc będę próbować rozwinąć dlaczego wolę ten styl.
Nie poleciłbym ujawnienia Twojej OOAD przez DTO w oddzielnej warstwie, co zazwyczaj prowadzi do nadęty interfejs, gdzie przekazuje się wiele danych, które nie są używane i religijnie mapować go do iz tego, co jest zasadniczo kopią modelu domeny z usuniętą logiką, a ja po prostu nie widzę wartości. Zwykle tworzę warstwę usług wokół operacji, które ona eksponuje i używam DTO do definiowania interakcji usług.
Używanie DTO opartych na narażonych operacjach, a nie w modelu domeny, pomaga utrzymać enkapsulację usługi i zmniejsza sprzężenie z modelem domeny. Nie ujawniając mojego modelu domeny, nie muszę robić żadnych kompromisów w zakresie widoczności pola lub dziedziczenia w celu serializacji.
np jakbym narażając metodę przenoszenia z jednego konta na drugie interfejs usługi będzie wyglądać mniej więcej tak:
[ServiceContract]
interface ISomeService
{
[OperationContract]
TransferResult Transfer(TransferRequest request);
}
[DataContract]
class TransferRequest
{
[DataMember]
public string FromAccountNumber {get;set;}
[DataMember]
public string ToAccountNumber {get;set;}
[DataMember]
public Money Amount {get;set;}
}
class SomeService : ISomeService
{
TransferResult Transfer(TransferRequest request)
{
//Check parameters...omitted for clarity
var from = repository.Load<Account>(request.FromAccountNumber);
//Assert that the caller is authorised to request transfer on this account
var to = repository.Load<Account>(request.ToAccountNumber);
from.Transfer(to, request.Amount);
//Build an appropriate response (or fault)
}
}
teraz z tego interfejsu to do conusmer bardzo jasne, co wymagane dane do zadzwoń do tej operacji. Gdybym to realizowane jako
[ServiceContract]
interface ISomeService
{
[OperationContract]
TransferResult Transfer(AccountDto from, AccountDto to, MoneyDto dto);
}
i AccountDto jest kopią pól w koncie, jako konsumenta, które pola należy wypełnić ja? Wszyscy? Jeśli dodano nową właściwość do obsługi nowej operacji, wszyscy użytkownicy wszystkich operacji mogą teraz zobaczyć tę właściwość. WCF pozwala mi oznaczyć tę właściwość jako nieobowiązkową, tak aby nie złamać wszystkich moich innych klientów, ale jeśli jest ona obowiązkowa dla nowej operacji, klient dowie się dopiero, gdy wywoła operację.
Co gorsza, jako realizator usług, co się stanie, jeśli zapewnią mi bieżące saldo? powinienem mu ufać?
Ogólna zasada polega na zapytaniu, kto jest właścicielem danych, klienta lub usługi? Jeśli klient jest jej właścicielem, może przekazać go do usługi i po wykonaniu podstawowych kontroli usługa może z niego skorzystać. Jeśli usługa jest jego właścicielem, klient powinien przekazać tylko tyle informacji, aby usługa mogła pobrać to, czego potrzebuje. Dzięki temu usługa może zachować spójność danych, które posiada.
W tym przykładzie usługa jest właścicielem informacji o koncie, a kluczem do zlokalizowania jest numer konta. Chociaż usługa może potwierdzić kwotę (jest dodatnia, obsługiwana waluta itp.), Jest własnością klienta i dlatego oczekujemy, że wszystkie pola w DTO zostaną wypełnione.
Podsumowując, widziałem to wszystko na trzy sposoby, ale projektowanie DTO wokół konkretnych operacji było zdecydowanie najbardziej udane, zarówno z wdrożenia usługowego, jak i konsumenckiego. Pozwala to na niezależną ewolucję operacji i bardzo jasno określa, czego oczekuje się od usługi i co zostanie zwrócone klientowi.
Jeśli to zadanie domowe, oznacz to jako takie. –
@HenkHolterman To nie jest praca domowa. Zostałem przydzielony do nowego projektu, który wykorzystuje SOA. Chociaż wcześniej korzystałem z WCF, to nie korzystałem z architektury SOA. Próbuję poznać koncepcje SOA. – Lijo