Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W przykładzie AdvancedDispatchByBody pokazano, jak zaimplementować alternatywny algorytm przypisywania komunikatów przychodzących do operacji.
Domyślnie mechanizm obsługi modelu usługi wybiera odpowiednią metodę obsługi dla komunikatu przychodzącego na podstawie nagłówka "Akcja" oznaczonego WS-Addressing lub równoważnych informacji w żądaniu HTTP SOAP.
Niektóre stosy usług sieci Web protokołu SOAP 1.1, które nie są zgodne z wytycznymi WS-I Basic Profile 1.1, nie wysyłają komunikatów na podstawie identyfikatora URI akcji, ale raczej na podstawie kwalifikowanej nazwy XML pierwszego elementu wewnątrz treści protokołu SOAP. Podobnie strona klienta w ramach tych stosów może wysyłać komunikaty z pustym lub dowolnym nagłówkiem protokołu HTTP SoapAction, który był dozwolony przez specyfikację protokołu SOAP 1.1.
Aby zmienić sposób przesyłania wiadomości do metod, przykład implementuje IDispatchOperationSelector interfejs rozszerzalności na DispatchByBodyElementOperationSelector. Ta klasa wybiera operacje na podstawie pierwszego elementu treści komunikatu.
Konstruktor klasy oczekuje słownika wypełnionego parami kluczy XmlQualifiedName i ciągów znaków, gdzie pełne nazwy wskazują nazwę pierwszego elementu w ciele SOAP, a ciągi wskazują odpowiednią nazwę operacji. Jest to defaultOperationName, nazwa operacji, która odbiera wszystkie komunikaty, które nie pasują do tego słownika.
class DispatchByBodyElementOperationSelector : IDispatchOperationSelector
{
Dictionary<XmlQualifiedName, string> dispatchDictionary;
string defaultOperationName;
public DispatchByBodyElementOperationSelector(Dictionary<XmlQualifiedName,string> dispatchDictionary, string defaultOperationName)
{
this.dispatchDictionary = dispatchDictionary;
this.defaultOperationName = defaultOperationName;
}
}
IDispatchOperationSelector implementacje są bardzo proste do skompilowania, ponieważ w interfejsie istnieje tylko jedna metoda: SelectOperation. Zadaniem tej metody jest sprawdzenie przychodzącej wiadomości i zwrócenie ciągu znaków odpowiadającego nazwie metody w kontrakcie usługi dla bieżącego punktu końcowego.
W tym przykładzie selektor operacji uzyskuje element XmlDictionaryReader dla treści wiadomości przychodzącej przy użyciu polecenia GetReaderAtBodyContents. Ta metoda umieszcza już czytelnika w pierwszym elemencie podrzędnym treści komunikatu, dzięki czemu wystarczy uzyskać nazwę bieżącego elementu i identyfikator URI przestrzeni nazw, a następnie połączyć je w element XmlQualifiedName , który jest następnie używany do wyszukiwania odpowiedniej operacji z słownika przechowywanego przez selektor operacji.
public string SelectOperation(ref System.ServiceModel.Channels.Message message)
{
XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
XmlQualifiedName lookupQName = new
XmlQualifiedName(bodyReader.LocalName, bodyReader.NamespaceURI);
message = CreateMessageCopy(message,bodyReader);
if (dispatchDictionary.ContainsKey(lookupQName))
{
return dispatchDictionary[lookupQName];
}
else
{
return defaultOperationName;
}
}
Uzyskiwanie dostępu do treści komunikatu za pomocą GetReaderAtBodyContents dowolnej z innych metod zapewniających dostęp do treści wiadomości powoduje oznaczenie komunikatu jako "odczyt", co oznacza, że komunikat jest nieprawidłowy w przypadku dalszego przetwarzania. W związku z tym selektor operacji tworzy kopię komunikatu przychodzącego przy użyciu metody pokazanej w poniższym kodzie. Ponieważ pozycja czytelnika nie została zmieniona podczas inspekcji, nowo utworzony komunikat może odwoływać się do niej. Do tego komunikatu kopiowane są również właściwości i nagłówki wiadomości, co skutkuje dokładnym sklonowaniem oryginalnej wiadomości.
private Message CreateMessageCopy(Message message,
XmlDictionaryReader body)
{
Message copy = Message.CreateMessage(message.Version,message.Headers.Action,body);
copy.Headers.CopyHeaderFrom(message,0);
copy.Properties.CopyProperties(message.Properties);
return copy;
}
Dodawanie selektora operacji do usługi
Selektory operacji wysyłania usługi to rozszerzenia dyspozytora programu Windows Communication Foundation (WCF). W przypadku wybierania metod w kanale wywołania zwrotnego kontraktów dwukierunkowych istnieją również selektory operacji klienta, które działają bardzo podobnie jak selektory operacji wysyłania opisane tutaj, ale które nie są jawnie omówione w tym przykładzie.
Podobnie jak w przypadku większości rozszerzeń modelu usługi selektory operacji wysyłania są dodawane do dyspozytora przy użyciu zachowań. Zachowanie to obiekt konfiguracji, który dodaje jedno lub więcej rozszerzeń do procesu uruchomieniowego wysyłki (lub środowiska uruchomieniowego klienta), albo w inny sposób zmienia jego ustawienia.
Ponieważ selektory operacji mają zakres kontraktu, odpowiednie zachowanie do zaimplementowania w tym miejscu to IContractBehavior. Ponieważ interfejs jest implementowany w klasie pochodnej Attribute , jak pokazano w poniższym kodzie, zachowanie można deklaratywnie dodać do dowolnego kontraktu usługi. Za każdym razem, gdy ServiceHost jest otwierane i środowisko uruchomieniowe wysyłania jest budowane, wszystkie zachowania znalezione jako atrybuty na kontraktach, operacjach, oraz implementacjach usług lub jako element w konfiguracji usługi są automatycznie dodawane, a następnie proszone o współtworzenie rozszerzeń lub modyfikowanie konfiguracji domyślnej.
W przypadku zwięzłości poniższy fragment kodu pokazuje tylko implementację metody ApplyDispatchBehavior, która wpływa na zmiany konfiguracji dyspozytora w tym przykładzie. Inne metody nie są wyświetlane, ponieważ wracają do wywołującego bez wykonywania żadnej pracy.
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface)]
class DispatchByBodyElementBehaviorAttribute : Attribute, IContractBehavior
{
// public void AddBindingParameters(...)
// public void ApplyClientBehavior(...)
// public void Validate(...)
Najpierw implementacja ApplyDispatchBehavior konfiguruje słownik wyszukiwania dla selektora operacji, poprzez iterację nad elementami OperationDescription w punkcie końcowym usługi ContractDescription. Następnie każdy opis operacji jest sprawdzany pod kątem obecności DispatchBodyElementAttribute zachowania, implementacji IOperationBehavior , która jest również zdefiniowana w tym przykładzie. Chociaż ta klasa jest również zachowaniem, jest pasywna i nie przyczynia się aktywnie do żadnych zmian konfiguracji w czasie wykonywania dyspozycji. Wszystkie jego metody wracają do wywołującego bez wykonywania żadnych akcji. Zachowanie operacji istnieje tylko tak, aby metadane wymagane dla nowego mechanizmu wysyłania, a mianowicie kwalifikowana nazwa elementu treści, na którym wybrano wystąpienie operacji, można skojarzyć z odpowiednimi operacjami.
Jeśli takie zachowanie zostanie znalezione, do słownika zostanie dodana para wartości utworzona na podstawie kwalifikowanej nazwy w XML (QName właściwość) oraz nazwy operacji (Name właściwość).
Po wypełnieniu słownika zostanie utworzony nowy DispatchByBodyElementOperationSelector element zawierający te informacje i ustawiony jako selektor operacji środowiska uruchomieniowego wysyłania:
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
{
Dictionary<XmlQualifiedName,string> dispatchDictionary =
new Dictionary<XmlQualifiedName,string>();
foreach( OperationDescription operationDescription in
contractDescription.Operations )
{
DispatchBodyElementAttribute dispatchBodyElement =
operationDescription.Behaviors.Find<DispatchBodyElementAttribute>();
if ( dispatchBodyElement != null )
{
dispatchDictionary.Add(dispatchBodyElement.QName,
operationDescription.Name);
}
}
dispatchRuntime.OperationSelector =
new DispatchByBodyElementOperationSelector(
dispatchDictionary,
dispatchRuntime.UnhandledDispatchOperation.Name);
}
}
Implementowanie usługi
Zachowanie zaimplementowane w tym przykładzie bezpośrednio wpływa na sposób interpretowania i wysyłania komunikatów z przewodu, co jest funkcją kontraktu usługi. W związku z tym zachowanie powinno zostać zadeklarowane na poziomie kontraktu usługi w dowolnej implementacji usługi, która wybierze jej użycie.
Przykładowa usługa projektowa stosuje zachowanie kontraktu DispatchByBodyElementBehaviorAttribute do kontraktu usługi IDispatchedByBody i oznacza każdą z dwóch operacji OperationForBodyA() oraz OperationForBodyB() zachowaniem operacji DispatchBodyElementAttribute. Po otwarciu hosta usługi dla usługi, która implementuje ten kontrakt, te metadane są pobierane przez kompilator dyspozytora, jak opisano wcześniej.
Ponieważ selektor operacji wysyła wyłącznie na podstawie elementu treści komunikatu i ignoruje wartość "Akcja", należy poinformować środowisko uruchomieniowe, aby nie sprawdzało nagłówka "Akcja" w zwróconych odpowiedziach, przypisując symbol wieloznaczny "*" do właściwości ReplyActionOperationContractAttribute. Ponadto wymagana jest domyślna operacja, która ma właściwość "Action" ustawioną na symbol wieloznaczny "*". Domyślna operacja odbiera wszystkie komunikaty, których nie można wysłać i nie ma elementu DispatchBodyElementAttribute:
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples"),
DispatchByBodyElementBehavior]
public interface IDispatchedByBody
{
[OperationContract(ReplyAction="*"),
DispatchBodyElement("bodyA","http://tempuri.org")]
Message OperationForBodyA(Message msg);
[OperationContract(ReplyAction = "*"),
DispatchBodyElement("bodyB", "http://tempuri.org")]
Message OperationForBodyB(Message msg);
[OperationContract(Action="*", ReplyAction="*")]
Message DefaultOperation(Message msg);
}
Przykładowa implementacja usługi jest prosta. Każda metoda opakowuje odebraną wiadomość w wiadomość odpowiedzi i przesyła ją z powrotem do klienta.
Uruchamianie i kompilowanie przykładu
Gdy uruchomisz przykładowy program, treść odpowiedzi operacji jest wyświetlana w konsoli klienta podobnie do następującego (sformatowanego) wyniku.
Klient wysyła do usługi trzy komunikaty, których element zawartości treści ma nazwę bodyA, bodyBi bodyX, odpowiednio. Jak można wywnioskować z poprzedniego opisu oraz pokazanego kontraktu serwisowego, przychodzący komunikat z elementem bodyA jest wysyłany do metody OperationForBodyA(). Ponieważ nie ma jawnego docelowego adresata dla komunikatu zawierającego element bodyX treści, komunikat jest wysyłany do DefaultOperation(). Każda operacja usługi opakowuje treść odebranego komunikatu do elementu specyficznego dla metody i zwraca ją, co jest wykonywane w celu korelowania komunikatów wejściowych i wyjściowych wyraźnie dla tego przykładu:
<?xml version="1.0" encoding="IBM437"?>
<replyBodyA xmlns="http://tempuri.org">
<q:bodyA xmlns:q="http://tempuri.org">test</q:bodyA>
</replyBodyA>
<?xml version="1.0" encoding="IBM437"?>
<replyBodyB xmlns="http://tempuri.org">
<q:bodyB xmlns:q="http://tempuri.org">test</q:bodyB>
</replyBodyB>
<?xml version="1.0" encoding="IBM437"?>
<replyDefault xmlns="http://tempuri.org">
<q:bodyX xmlns:q="http://tempuri.org">test</q:bodyX>
</replyDefault>
Aby skonfigurować, skompilować i uruchomić przykładowy program
Upewnij się, że wykonano procedurę instalacji One-Time dla przykładów programu Windows Communication Foundation.
Aby skompilować rozwiązanie, postępuj zgodnie z instrukcjami w temacie Building the Windows Communication Foundation Samples (Tworzenie przykładów programu Windows Communication Foundation).
Aby uruchomić przykład w konfiguracji pojedynczej lub między maszynami, postępuj zgodnie z instrukcjami w Uruchamianie przykładów programu Windows Communication Foundation.