Benutzerdefinierte Lebensdauer
In diesem Beispiel wird veranschaulicht, wie eine Windows Communication Foundation (WCF)-Erweiterung geschrieben wird, die benutzerdefinierte Lebensdauerdienste für freigegebene WCF-Dienstinstanzen bereitstellen soll.
Hinweis: |
---|
Die Setupprozedur und die Erstellungsanweisungen für dieses Beispiel befinden sich am Ende dieses Abschnitts. |
Freigegebene Instanziierung
WCF stellt mehrere Instanziierungsmodi für die Dienstinstanzen bereit. Der freigegebene Instanziierungsmodus, der in diesem Thema behandelt wird, bietet eine Möglichkeit, eine Dienstinstanz zwischen mehreren Kanälen freizugeben. Clients können entweder die Endpunktadresse der Instanz lokal auflösen oder eine Factorymethode im Dienst kontaktieren, um die Endpunktadresse einer ausgeführten Instanz abzurufen. Sobald die Endpunktadresse vorliegt, kann ein neuer Kanal erstellt und die Kommunikation gestartet werden. Im folgenden Codeausschnitt wird gezeigt, wie eine Clientanwendung einen neuen Kanal zu einer vorhandenen Dienstinstanz erstellt.
// Create the first channel.
IEchoService proxy = channelFactory.CreateChannel();
// Resolve the instance.
EndpointAddress epa = ((IClientChannel)proxy).ResolveInstance();
// Create new channel factory with the endpoint address resolved by
// previous statement.
ChannelFactory<IEchoService> channelFactory2 =
new ChannelFactory<IEchoService>("echoservice",
epa);
// Create the second channel to the same instance.
IEchoService proxy2 = channelFactory2.CreateChannel();
Der freigegebene Instanziierungsmodus unterscheidet sich von anderen Instanziierungsmodi in seiner einzigartigen Methode zum Freigeben von Dienstinstanzen. Wenn alle Kanäle für eine Instanz geschlossen sind, startet die WCF-Laufzeit des Diensts einen Zeitgeber. Wenn vor Ablauf des Timeouts keine Verbindung hergestellt wird, gibt WCF die Instanz frei und erhebt Anspruch auf die Ressourcen. Im Rahmen der Beendigungsprozedur ruft WCF die IsIdle-Methode aller IShareableInstanceContextLifetime-Implementierungen auf, bevor die Instanz freigegeben wird. Wenn alle Implementierungen true zurückgeben, wird die Instanz freigegeben. Andernfalls ist die IShareableInstanceContextLifetime-Implementierung dafür zuständig, den Dispatcher unter Verwendung einer Rückrufmethode von dem Leerlaufzustand zu benachrichtigen.
Standardmäßig beträgt der Leerlauftimeoutwert von InstanceContext eine Minute. In diesem Beispiel wird jedoch gezeigt, wie Sie diesen Wert erweitern können, indem Sie die benutzerdefinierte Erweiterung verwenden.
Erweitern von InstanceContext
In WCF stellt InstanceContext die Verbindung zwischen der Dienstinstanz und dem Dispatcher dar. Sie können diese Laufzeitkomponente in WCF erweitern, indem Sie mithilfe des erweiterbaren Objektmusters einen neuen Zustand oder ein neues Verhalten hinzufügen. Das erweiterbare Objektmuster wird in WCF verwendet, um vorhandene Laufzeitklassen um neue Funktionen zu erweitern oder um neue Zustandsfunktionen zu einem Objekt hinzuzufügen. Es gibt drei Schnittstellen im erweiterbaren Objektmuster: IExtensibleObject<T>, IExtension<T> und IExtensionCollection<T>.
Die IExtensibleObject<T>-Schnittstelle wird von Objekten implementiert, um Erweiterungen zuzulassen, die ihre Funktionalität anpassen.
Die IExtension<T>-Schnittstelle wird von Objekten implementiert, die Erweiterungen von Klassen des Typs T sein können.
Die IExtensionCollection<T>-Schnittstelle ist eine Auflistung von IExtensions, die das Abrufen von IExtensions nach Typ zulässt.
Aus diesem Grund müssen Sie die IExtension-Schnittstelle implementieren, um den InstanceContext zu erweitern. In diesem Beispielprojekt enthält die CustomLeaseExtension
-Klasse diese Implementierung.
class CustomLeaseExtension : IExtension<InstanceContext>
{
}
Die IExtension-Schnittstelle verfügt über zwei Methoden: Attach und Detach. Wie ihre Namen vermuten lassen, werden diese beiden Methoden aufgerufen, wenn die Laufzeit die Erweiterung an eine Instanz der InstanceContext-Klasse anfügt oder von der Instanz löst. In diesem Beispiel wird die Attach-Methode für die Nachverfolgung des InstanceContext-Objekts verwendet, das zur aktuellen Instanz der Erweiterung gehört.
InstanceContext owner;
public void Attach(InstanceContext owner)
{
this.owner = owner;
}
Darüber hinaus müssen Sie zur Bereitstellung der erweiterten Lebensdauerunterstützung die erforderliche Implementierung zur Erweiterung hinzufügen. Deswegen wird die ICustomLease
-Schnittstelle mit den gewünschten Methoden deklariert und in der CustomLeaseExtension-Klasse implementiert.
interface ICustomLease
{
bool IsIdle { get; }
InstanceContextIdleCallback Callback { get; set; }
}
class CustomLeaseExtension : IExtension<InstanceContext>, ICustomLease
{
}
Wenn in WCF die IsIdle-Methode in der IShareableInstanceContextLifetime-Implementierung aufgerufen wird, wird dieser Aufruf an die IsIdle-Methode der CustomLeaseExtension
weitergeleitet. Dann überprüft die CustomLeaseExtension
den privaten Zustand, um festzustellen, ob sich der InstanceContext im Leerlauf befindet. Wenn er sich in Leerlauf befindet, wird true zurückgegeben. Andernfalls wird ein Zeitgeber für eine bestimmte erweiterte Lebensdauerperiode gestartet.
public bool IsIdle
{
get
{
lock (thisLock)
{
if (isIdle)
{
return true;
}
else
{
StartTimer();
return false;
}
}
}
}
Im Elapsed
-Ereignis des Zeitgebers wird die Rückruffunktion im Verteiler aufgerufen, um einen weiteren Bereinigungszyklus zu starten.
void idleTimer_Elapsed(object sender, ElapsedEventArgs args)
{
idleTimer.Stop();
isIdle = true;
callback(owner);
}
Der ausgeführte Zeitgeber kann nicht erneuert werden, wenn eine neue Nachricht für die Instanz eingeht, die in den Leerlaufzustand verschoben wird.
Im Beispiel wird IShareableInstanceContextLifetime implementiert, um die Aufrufe der IsIdle-Methode abzufangen und diese zur CustomLeaseExtension
weiterzuleiten. Die IShareableInstanceContextLifetime-Implementierung ist in der CustomLifetimeLease
-Klasse enthalten. Die IsIdle-Methode wird aufgerufen, wenn WCF im Begriff ist, die Dienstinstanz freizugeben. Es gibt jedoch nur eine Instanz einer bestimmten ISharedSessionInstance
-Implementierung in der InstanceContextLifetimes-Auflistung von ServiceBehavior. Das bedeutet, dass nicht vorhergesagt werden kann, ob InstanceContext geschlossen ist, wenn WCF die IsIdle-Methode überprüft. Aus diesem Grund werden Anforderungen der IsIdle-Methode in diesem Beispiel mit der Threadsperre serialisiert.
Hinweis: |
---|
Die Verwendung der Threadsperre wird nicht empfohlen, da die Leistung der Anwendung durch die Serialisierung deutlich beeinträchtigt werden kann. |
Eine private Membervariable wird in der CustomLeaseExtension
-Klasse verwendet, um den IsIdle
-Wert nachzuverfolgen. Jedes Mal, wenn der Wert von IShareableInstanceContextLifetime abgerufen wird, wird der private IsIdle
-Member zurückgegeben und auf false zurückgesetzt. Dieser Wert muss auf false festgelegt werden, um sicherzustellen, dass der Verteiler die NotifyIdle-Methode aufruft.
public bool IsIdle
{
get
{
lock (thisLock)
{
bool idleCopy = isIdle;
isIdle = false;
return idleCopy;
}
}
}
Wenn die ISharedSessionLifetime.IsIdle
-Eigenschaft false zurückgibt, registriert der Verteiler mithilfe der NotifyIdle
-Methode eine Rückruffunktion. Diese Methode empfängt einen Verweis darauf, dass InstanceContext freigegeben wird. Daher kann der Beispielcode die Erweiterung des Typs ICustomLease
abfragen und die ICustomLease.IsIdle
-Eigenschaft im erweiterten Zustand überprüfen.
public void NotifyIdle(InstanceContextIdleCallback callback,
InstanceContext instanceContext)
{
lock (thisLock)
{
ICustomLease customLease =
instanceContext.Extensions.Find<ICustomLease>();
customLease.Callback = callback;
isIdle = customLease.IsIdle;
if (isIdle)
{
callback(instanceContext);
}
}
}
Bevor die ICustomLease.IsIdle
-Eigenschaft überprüft wird, muss die Rückrufeigenschaft festgelegt werden, damit die CustomLeaseExtension
den Verteiler benachrichtigen kann, sobald sie in den Leerlauf wechselt. Wenn ICustomLease.IsIdle
true zurückgibt, wird der private isIdle
-Member einfach in CustomLifetimeLease
auf true festgelegt, und die Rückrufmethode wird vom Member aufgerufen. Da im Code eine Sperre enthalten ist, können andere Threads den Wert dieses privaten Members nicht ändern. Wenn der Verteiler das nächste Mal die ISharedSessionLifetime.IsIdle
-Eigenschaft überprüft, gibt sie true zurück, und der Verteiler kann die Instanz freigeben.
Jetzt da die Vorarbeit für die benutzerdefinierte Erweiterung abgeschlossen ist, muss sie in das Dienstmodell eingebunden werden. Um die CustomLeaseExtension
-Implementierung in den InstanceContext einzubinden, stellt WCF die IInstanceContextInitializer-Schnittstelle bereit, um das Bootstrapping von InstanceContext auszuführen. In diesem Beispiel implementiert die CustomLeaseInitializer
-Klasse diese Schnittstelle und fügt eine CustomLeaseExtension
-Instanz zur Extensions-Auflistung aus der einzigen Methodeninitialisierung hinzu. Diese Methode wird vom Verteiler aufgerufen, während InstanceContext initialisiert wird.
public void Initialize(InstanceContext instanceContext, Message message)
{
IExtension<InstanceContext> customLeaseExtension =
new CustomLeaseExtension(timeout);
instanceContext.Extensions.Add(customLeaseExtension);
}
Schließlich werden die IShareableInstanceContextLifetime-Implementierung und die IInstanceContextInitializer-Implementierung in das Dienstmodell mithilfe der IServiceBehavior-Implementierung eingebunden. Diese Implementierung wird in der CustomLeaseTimeAttribute
-Klasse eingefügt, und sie wird außerdem von der Attribute
-Basisklasse abgeleitet, um dieses Verhalten als Attribut verfügbar zu machen. In der IServiceBehavior.ApplyBehavior
-Methode werden Instanzen von der IInstanceContextInitializer-Implementierung und der IShareableInstanceContextLifetime-Implementierung zu der InstanceContextLifetimes-Auflistung bzw. der InstanceContextInitializers-Auflistung von System.ServiceModel.Dispatcher hinzugefügt.
public void ApplyBehavior(ServiceDescription description,
ServiceHostBase serviceHostBase,
Collection<DispatchBehavior> behaviors,
Collection<BindingParameterCollection> parameters)
{
CustomLifetimeLease customLease = new CustomLifetimeLease();
CustomLeaseInitializer initializer =
new CustomLeaseInitializer(timeout);
foreach (DispatchBehavior dispatchBehavior in behaviors)
{
dispatchBehavior.InstanceContextLifetimes.Add(customLease);
dispatchBehavior.InstanceContextInitializers.Add(initializer);
}
}
Dieses Verhalten kann einer Beispieldienstklasse hinzugefügt werden, indem es mit dem CustomLeaseTime
-Attribut kommentiert wird.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Shareable)]
[CustomLeaseTime(Timeout = 20000)]
public class EchoService : IEchoService
{
//…
}
Wenn Sie das Beispiel ausführen, werden die Anforderungen und Antworten für den Vorgang im Dienst- und Clientkonsolenfenster angezeigt. Drücken Sie die EINGABETASTE in den einzelnen Konsolenfenstern, um den Dienst und den Client zu schließen.
So richten Sie das Beispiel ein, erstellen es und führen es aus
Stellen Sie sicher, dass Sie Einmaliges Setupverfahren für Windows Communication Foundation-Beispiele ausgeführt haben.
Zum Erstellen der C#- oder Visual Basic .NET-Edition der Projektmappe befolgen Sie die unter Erstellen der Windows Communication Foundation-Beispiele aufgeführten Anweisungen.
Wenn Sie das Beispiel in einer Konfiguration mit einem Computer oder über Computer hinweg ausführen möchten, folgen Sie den unter Running the Windows Communication Foundation Samples aufgeführten Anweisungen.
Hinweis: |
---|
Die Beispiele sind möglicherweise bereits auf dem Computer installiert. Überprüfen Sie das folgende (standardmäßige) Verzeichnis, bevor Sie fortfahren.
<Installationslaufwerk>:\WF_WCF_Samples
Wenn dieses Verzeichnis nicht vorhanden ist, rufen Sie Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 auf, um alle Windows Communication Foundation (WCF)- und WF-Beispiele herunterzuladen. Dieses Beispiel befindet sich im folgenden Verzeichnis.
<Installationslaufwerk>:\WF_WCF_Samples\WCF\Extensibility\Instancing\Lifetime
|