Jegyzet
Az oldalhoz való hozzáférés engedélyezést igényel. Próbálhatod be jelentkezni vagy könyvtárat váltani.
Az oldalhoz való hozzáférés engedélyezést igényel. Megpróbálhatod a könyvtár váltását.
Az AdvancedDispatchByBody minta bemutatja, hogyan implementálhat egy alternatív algoritmust a bejövő üzenetek műveletekhez való hozzárendeléséhez.
Alapértelmezés szerint a szolgáltatásmodell-diszpécser kiválasztja a megfelelő kezelési módszert egy bejövő üzenethez az üzenet WS-Addressing "Művelet" fejléce vagy a HTTP SOAP-kérelem megfelelő információi alapján.
Egyes SOAP 1.1 webszolgáltatás-veremek, amelyek nem követik az WS-I Alapprofil 1.1 irányelveit, nem a művelet URI-ja alapján küldenek üzeneteket, hanem a SOAP törzsében lévő első elem XML-minősített neve alapján. Hasonlóképpen, ezeknek a stackeknek az ügyféloldala üres vagy véletlenszerű HTTP SoapAction fejléccel küldhet üzeneteket, amelyet a SOAP 1.1 specifikációja megengedett.
Az üzenetek metódusokra való küldésének módosításához a minta implementálja a IDispatchOperationSelector bővíthetőségi felületet a DispatchByBodyElementOperationSelector. Ez az osztály az üzenet törzsének első eleme alapján választja ki a műveleteket.
Az osztálykonstruktor egy olyan szótárt vár, amely párokkal XmlQualifiedName és sztringekkel van feltöltve. A minősített nevek a SOAP törzs első gyermekének nevét, a sztringek pedig az egyező művelet nevét jelzik. Annak defaultOperationName a műveletnek a neve, amely minden olyan üzenetet fogad, amely nem felel meg ennek a szótárnak:
class DispatchByBodyElementOperationSelector : IDispatchOperationSelector
{
Dictionary<XmlQualifiedName, string> dispatchDictionary;
string defaultOperationName;
public DispatchByBodyElementOperationSelector(Dictionary<XmlQualifiedName,string> dispatchDictionary, string defaultOperationName)
{
this.dispatchDictionary = dispatchDictionary;
this.defaultOperationName = defaultOperationName;
}
}
IDispatchOperationSelector implementációk nagyon egyszerű építeni, mivel csak egy módszer a felületen: SelectOperation. Ennek a metódusnak a feladata egy bejövő üzenet vizsgálata és egy olyan sztring visszaadása, amely megegyezik az aktuális végpont szolgáltatási szerződésében szereplő metódus nevével.
Ebben a mintában a műveletválasztó megszerez egy XmlDictionaryReader elemet a bejövő üzenet törzséhez a GetReaderAtBodyContents használatával. Ez a módszer már az üzenet törzsének első gyermekéhez helyezi az olvashatót, így elegendő az aktuális elem nevének és névterének URI-jának lekérése, majd ezek kombinálása egy XmlQualifiedName elembe, amelyet a műveletválasztó által birtokolt szótárban található megfelelő művelet keresésére lehet használni.
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;
}
}
Az üzenet törzsének elérése GetReaderAtBodyContents vagy bármely más, az üzenet törzséhez hozzáférést biztosító módszerrel az üzenetet "olvasottként" jelöli meg, ami azt jelenti, hogy az üzenet minden további feldolgozásra érvénytelen lesz. Ezért a műveletválasztó létrehoz egy másolatot a bejövő üzenetről az alábbi kódban látható módszerrel. Mivel az olvasó pozíciója nem változott az ellenőrzés során, az újonnan létrehozott üzenet hivatkozhat rá, amelybe az üzenet tulajdonságai és az üzenetfejlécek is másolódnak, ami az eredeti üzenet pontos klónozását eredményezi:
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;
}
Műveletválasztó hozzáadása egy szolgáltatáshoz
A szolgáltatásküldési műveletválasztók a Windows Communication Foundation (WCF) diszpécser bővítményei. A duplex szerződések visszahívási csatornáján történő metódusok kiválasztásához léteznek ügyfélművelet-választók is, amelyek nagyon hasonlóan működnek, mint az itt leírt küldési műveletválasztók, de ezekre a mintában nincs explicit módon kitérve.
A legtöbb szolgáltatásmodell-bővítményhez hasonlóan a diszpécserhez viselkedések alkalmazásával adják hozzá a kiküldési műveletválasztókat. A viselkedés egy konfigurációs objektum, amely vagy hozzáad egy vagy több bővítményt a küldési futtatókörnyezethez (vagy az ügyfél futtatókörnyezetéhez), vagy más módon módosítja annak beállításait.
Mivel a műveletválasztók szerződési hatókörrel rendelkeznek, az itt implementálandó megfelelő viselkedés a IContractBehavior. Mivel a felület egy Attribute származtatott osztályon van implementálva, ahogyan az a következő kódban látható, a viselkedés deklaratív módon hozzáadható bármely szolgáltatási szerződéshez. Amikor megnyílik egy ServiceHost, és a feldolgozási környezet felépül, a rendszer automatikusan hozzáadja az összes viselkedést, amelyeket akár a szerződések, műveletek és szolgáltatás-implementációk attribútumaiként, vagy elemeként talál a szolgáltatáskonfigurációban, és ezt követően felkéri azokat, hogy járuljanak hozzá bővítményekkel, vagy módosítsák az alapértelmezett konfigurációt.
A rövidség kedvéért az alábbi kódrészlet csak a metódus ApplyDispatchBehaviorimplementálását mutatja be, ami hatással van a mintában szereplő diszpécser konfigurációs változásaira. A többi metódus nem látható, mert anélkül térnek vissza a hívóhoz, hogy bármilyen munkát végeznének.
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface)]
class DispatchByBodyElementBehaviorAttribute : Attribute, IContractBehavior
{
// public void AddBindingParameters(...)
// public void ApplyClientBehavior(...)
// public void Validate(...)
Először a ApplyDispatchBehavior implementáció beállítja a műveletválasztó keresési szótárát a szolgáltatásvégpont OperationDescriptionelemeinek ContractDescription iterálásával. Ezután minden műveletleírást megvizsgálunk a DispatchBodyElementAttribute viselkedés jelenlétére, és annak IOperationBehavior implementációját is, amelyet ebben a mintában definiálunk. Bár ez az osztály szintén viselkedés, passzív, és nem járul hozzá aktívan a küldési futtatókörnyezet konfigurációs változásaihoz. Minden metódusa művelet nélkül tér vissza a hívóhoz. A művelet viselkedése csak azért létezik, hogy az új kézbesítési mechanizmushoz szükséges metaadatok, nevezetesen annak a törzselemnek a minősített neve, amelyen egy művelet van kiválasztva, társítható legyen a megfelelő műveletekkel.
Ha ilyen viselkedést talál, az XML-minősített névből (QName tulajdonságból) létrehozott értékpár és a műveletnév (Name tulajdonság) hozzáadódik a szótárhoz.
A szótár feltöltése után a rendszer létrehoz egy új DispatchByBodyElementOperationSelector-t ezzel az információval, és a küldési futtatási környezet műveletválasztójaként van beállítva.
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);
}
}
A szolgáltatás megvalósítása
Az ebben a mintában alkalmazott viselkedés közvetlenül befolyásolja a vezetékről érkező üzenetek értelmezését és küldését, ami a szolgáltatási szerződés egyik funkciója. Következésképpen a viselkedést a szolgáltatásszerződés szintjén kell deklarálni minden olyan szolgáltatás-implementációban, amely a használatát választja.
A mintaprojekt-szolgáltatás a DispatchByBodyElementBehaviorAttribute szerződés viselkedését alkalmazza a IDispatchedByBody szolgáltatási szerződésre, és a két műveletet, OperationForBodyA() és OperationForBodyB(), a DispatchBodyElementAttribute műveleti viselkedéssel látja el. A szerződést megvalósító szolgáltatás állomásának megnyitásakor ezt a metaadatokat a diszpécserkészítő a korábban ismertetett módon veszi át.
Mivel a műveletválasztó kizárólag az üzenet törzselemére támaszkodik, és figyelmen kívül hagyja a "Művelet" elemet, értesíteni kell a futtatókörnyezetet, hogy ne ellenőrizze a "Művelet" fejlécet a visszakapott válaszoknál, amit a "*" helyettesítő karakterrel lehet elérni a ReplyAction tulajdonságnál OperationContractAttribute. Emellett rendelkeznie kell egy alapértelmezett művelettel, amelynek "Action" tulajdonsága "*" helyettesítő karakterre van állítva. Az alapértelmezett művelet minden olyan üzenetet fogad, amely nem küldhető el, és nem rendelkezik DispatchBodyElementAttributea következővel:
[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);
}
A mintaszolgáltatás megvalósítása egyszerű. Minden metódus egy válaszüzenetbe burkolja a kapott üzenetet, és visszaküldi az ügyfélnek.
A minta futtatása és létrehozása
A minta futtatásakor a műveleti válaszok törzstartalma az ügyfélkonzol ablakában az alábbi (formázott) kimenethez hasonlóan jelenik meg.
Az ügyfél három üzenetet küld annak a szolgáltatásnak, amelyek törzstartalom-elemeinek nevei bodyA, bodyB, illetve bodyX. Ahogy az előző leírásból és a szolgáltatási szerződésből levezethető, a bodyA elemet tartalmazó bejövő üzenet a OperationForBodyA() metódushoz kerül továbbításra. Mivel nincs explicit küldési cél az üzenet számára, amely tartalmazza a bodyX törzselemet, az üzenet továbbításra kerül a DefaultOperation() számára. Minden szolgáltatásművelet a kapott üzenettörzset egy, a metódusra jellemző elembe burkolja, és visszaadja, amely a bemeneti és kimeneti üzeneteknek a mintához való egyértelmű korrelációja érdekében történik:
<?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>
A példa beállítása, elkészítése és futtatása
Győződjön meg arról, hogy elvégezte a Windows Communication Foundation-minták One-Time beállítási eljárását.
A megoldás létrehozásához kövesse a Windows Communication Foundation-minták készítésére vonatkozó utasításokat.
Ha a mintát egy vagy több gép közötti konfigurációban szeretné futtatni, kövesse A Windows Communication Foundation-minták futtatásacímű témakör utasításait.