Initialisatie van initialisatie
Het initialisatievoorbeeld breidt het poolvoorbeeld uit door een interface te definiëren, IObjectControl
waarmee de initialisatie van een object wordt aangepast door het te activeren en deactiveren. De client roept methoden aan die het object retourneren aan de pool en die het object niet retourneren aan de pool.
Notitie
De installatieprocedure en build-instructies voor dit voorbeeld bevinden zich aan het einde van dit onderwerp.
Uitbreidbaarheidspunten
De eerste stap bij het maken van een WCF-extensie (Windows Communication Foundation) is het bepalen van het uitbreidbaarheidspunt dat moet worden gebruikt. In WCF verwijst de term EndpointDispatcher naar een runtimeonderdeel dat verantwoordelijk is voor het converteren van binnenkomende berichten naar methodeaanroepen op de service van de gebruiker en voor het converteren van retourwaarden van die methode naar een uitgaand bericht. Een WCF-service maakt een EndpointDispatcher voor elk eindpunt.
EndpointDispatcher biedt eindpuntbereik (voor alle berichten die door de service zijn ontvangen of verzonden) met behulp van de EndpointDispatcher klasse. Met deze klasse kunt u verschillende eigenschappen aanpassen waarmee het gedrag van EndpointDispatcher wordt bepaald. Dit voorbeeld is gericht op de InstanceProvider eigenschap die verwijst naar het object dat de exemplaren van de serviceklasse levert.
IInstanceProvider
In WCF maakt EndpointDispatcher exemplaren van een serviceklasse met behulp van een exemplaarprovider die de IInstanceProvider interface implementeert. Deze interface heeft slechts twee methoden:
GetInstance: Wanneer een bericht binnenkomt, roept de dispatcher de GetInstance methode aan om een exemplaar van de serviceklasse te maken om het bericht te verwerken. De frequentie van de aanroepen naar deze methode wordt bepaald door de InstanceContextMode eigenschap. Als de InstanceContextMode eigenschap bijvoorbeeld is ingesteld InstanceContextMode.PerCallop, wordt er een nieuw exemplaar van de serviceklasse gemaakt om elk bericht te verwerken dat binnenkomt, dus GetInstance wanneer een bericht binnenkomt.
ReleaseInstance: Wanneer het service-exemplaar klaar is met het verwerken van het bericht, roept EndpointDispatcher de ReleaseInstance methode aan. Net als in de GetInstance methode wordt de frequentie van de aanroepen naar deze methode bepaald door de InstanceContextMode eigenschap.
De objectgroep
De ObjectPoolInstanceProvider
klasse bevat de implementatie voor de objectgroep. Met deze klasse wordt de IInstanceProvider interface geïmplementeerd om te communiceren met de servicemodellaag. Wanneer EndpointDispatcher de GetInstance methode aanroept in plaats van een nieuw exemplaar te maken, zoekt de aangepaste implementatie naar een bestaand object in een in-memory pool. Als er een beschikbaar is, wordt deze geretourneerd. Anders controleert ObjectPoolInstanceProvider
u of de ActiveObjectsCount
eigenschap (het aantal objecten dat wordt geretourneerd uit de pool) de maximale poolgrootte heeft bereikt. Als dat niet het geval is, wordt er een nieuw exemplaar gemaakt en geretourneerd naar de aanroeper en ActiveObjectsCount
vervolgens verhoogd. Anders wordt een aanvraag voor het maken van objecten in de wachtrij geplaatst voor een geconfigureerde periode. De implementatie voor GetObjectFromThePool
wordt weergegeven in de volgende voorbeeldcode.
private object GetObjectFromThePool()
{
bool didNotTimeout =
availableCount.WaitOne(creationTimeout, true);
if(didNotTimeout)
{
object obj = null;
lock (poolLock)
{
if (pool.Count != 0)
{
obj = pool.Pop();
activeObjectsCount++;
}
else if (pool.Count == 0)
{
if (activeObjectsCount < maxPoolSize)
{
obj = CreateNewPoolObject();
activeObjectsCount++;
#if (DEBUG)
WritePoolMessage(
ResourceHelper.GetString("MsgNewObject"));
#endif
}
}
idleTimer.Stop();
}
// Call the Activate method if possible.
if (obj is IObjectControl)
{
((IObjectControl)obj).Activate();
}
return obj;
}
throw new TimeoutException(
ResourceHelper.GetString("ExObjectCreationTimeout"));
}
Met de aangepaste implementatie wordt het uitgebrachte ReleaseInstance
exemplaar weer toegevoegd aan de pool en wordt de ActiveObjectsCount
waarde gedegraded. EndpointDispatcher kan deze methoden aanroepen vanuit verschillende threads en daarom is gesynchroniseerde toegang tot de leden op klasseniveau in de ObjectPoolInstanceProvider
klasse vereist.
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
lock (poolLock)
{
// Check whether the object can be pooled.
// Call the Deactivate method if possible.
if (instance is IObjectControl)
{
IObjectControl objectControl = (IObjectControl)instance;
objectControl.Deactivate();
if (objectControl.CanBePooled)
{
pool.Push(instance);
#if(DEBUG)
WritePoolMessage(
ResourceHelper.GetString("MsgObjectPooled"));
#endif
}
else
{
#if(DEBUG)
WritePoolMessage(
ResourceHelper.GetString("MsgObjectWasNotPooled"));
#endif
}
}
else
{
pool.Push(instance);
#if(DEBUG)
WritePoolMessage(
ResourceHelper.GetString("MsgObjectPooled"));
#endif
}
activeObjectsCount--;
if (activeObjectsCount == 0)
{
idleTimer.Start();
}
}
availableCount.Release(1);
}
De ReleaseInstance
methode biedt een functie voor het opschonen van initialisatie . Normaal gesproken onderhoudt de pool een minimum aantal objecten voor de levensduur van de pool. Er kunnen echter perioden zijn van overmatig gebruik waarvoor het maken van extra objecten in de groep nodig is om de maximale limiet te bereiken die is opgegeven in de configuratie. Wanneer de pool uiteindelijk minder actief wordt, kunnen deze overschotobjecten een extra overhead worden. Dus wanneer de activeObjectsCount
nul bereikt, wordt een niet-actieve timer gestart die wordt geactiveerd en een opschooncyclus uitvoert.
if (activeObjectsCount == 0)
{
idleTimer.Start();
}
ServiceModel-laagextensies worden gekoppeld met behulp van het volgende gedrag:
Servicegedrag: Hiermee kunt u de volledige serviceruntime aanpassen.
Eindpuntgedrag: Hiermee kunt u een bepaald service-eindpunt aanpassen, waaronder EndpointDispatcher.
Contractgedrag: Deze bieden respectievelijk de mogelijkheid om een of DispatchRuntime meer klassen op de client of de service aan te passenClientRuntime.
Bewerkingsgedrag: deze maken het mogelijk om respectievelijk klassen van DispatchOperation de client of de service aan te passenClientOperation.
Voor het doel van een objectpoolextensie kan een eindpuntgedrag of een servicegedrag worden gemaakt. In dit voorbeeld gebruiken we een servicegedrag, waarmee objectgroeperingsmogelijkheid wordt toegepast op elk eindpunt van de service. Servicegedrag wordt gemaakt door de IServiceBehavior interface te implementeren. Er zijn verschillende manieren om het ServiceModel bewust te maken van het aangepaste gedrag:
Een aangepast kenmerk gebruiken.
Imperatief toevoegen aan de gedragverzameling van de servicebeschrijving.
Het configuratiebestand uitbreiden.
In dit voorbeeld wordt een aangepast kenmerk gebruikt. Wanneer de ServiceHost service is samengesteld, worden de kenmerken onderzocht die worden gebruikt in de typedefinitie van de service en worden de beschikbare gedragingen toegevoegd aan de verzameling gedrag van de servicebeschrijving.
De IServiceBehavior interface heeft drie methoden: Validate,
,
AddBindingParametersen .ApplyDispatchBehavior Deze methoden worden aangeroepen door WCF wanneer de ServiceHost wordt geïnitialiseerd. IServiceBehavior.Validate wordt eerst aangeroepen; hiermee kan de service worden geïnspecteerd op inconsistenties. IServiceBehavior.AddBindingParameters wordt volgende aangeroepen; deze methode is alleen vereist in zeer geavanceerde scenario's. IServiceBehavior.ApplyDispatchBehavior wordt laatste aangeroepen en is verantwoordelijk voor het configureren van de runtime. De volgende parameters worden doorgegeven aan IServiceBehavior.ApplyDispatchBehavior:
Description
: Deze parameter bevat de servicebeschrijving voor de hele service. Dit kan worden gebruikt om beschrijvingsgegevens te controleren over de eindpunten, contracten, bindingen en andere gegevens die aan de service zijn gekoppeld.ServiceHostBase
: Deze parameter biedt de ServiceHostBase parameter die momenteel wordt geïnitialiseerd.
In de aangepaste IServiceBehavior implementatie wordt een nieuw exemplaar van ObjectPoolInstanceProvider
geïnstantieerd en toegewezen aan de InstanceProvider eigenschap in elk EndpointDispatcher exemplaar dat aan de ServiceHostBaseeigenschap is gekoppeld.
public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
{
if (enabled)
{
// Create an instance of the ObjectPoolInstanceProvider.
instanceProvider = new ObjectPoolInstanceProvider(description.ServiceType,
maxPoolSize, minPoolSize, creationTimeout);
// Assign our instance provider to Dispatch behavior in each
// endpoint.
foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = cdb as ChannelDispatcher;
if (cd != null)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.InstanceProvider = instanceProvider;
}
}
}
}
}
Naast een IServiceBehavior implementatie heeft de ObjectPoolingAttribute
klasse verschillende leden om de objectgroep aan te passen met behulp van de kenmerkargumenten. Deze leden omvatten MaxSize
, MinSize
Enabled
en CreationTimeout
, die overeenkomen met de functieset voor objectpooling die wordt geleverd door .NET Enterprise Services.
Het gedrag van objectpooling kan nu worden toegevoegd aan een WCF-service door aantekeningen te maken bij de service-implementatie met het zojuist gemaakte aangepaste ObjectPooling
kenmerk.
[ObjectPooling(MaxSize=1024, MinSize=10, CreationTimeout=30000]
public class PoolService : IPoolService
{
// …
}
Activering en deactivering koppelen
Het primaire doel van objectpooling is het optimaliseren van kortdurende objecten met relatief dure creatie en initialisatie. Daarom kan het een dramatische prestatie boost geven aan een toepassing als deze goed wordt gebruikt. Omdat het object wordt geretourneerd uit de pool, wordt de constructor slechts één keer aangeroepen. Voor sommige toepassingen is echter een bepaald controleniveau vereist, zodat ze de resources die tijdens één context worden gebruikt, kunnen initialiseren en opschonen. Een object dat wordt gebruikt voor een set berekeningen kan bijvoorbeeld de privévelden opnieuw instellen voordat de volgende berekening wordt verwerkt. Enterprise Services heeft dit type contextspecifieke initialisatie ingeschakeld door de objectontwikkelaar te laten overschrijven en Deactivate
methoden uit de ServicedComponent basisklasse te laten overschrijvenActivate
.
De objectgroep roept de Activate
methode aan net voordat het object uit de pool wordt geretourneerd. Deactivate
wordt aangeroepen wanneer het object terugkeert naar de pool. De ServicedComponent basisklasse heeft ook een eigenschap met de boolean
naam CanBePooled
, die kan worden gebruikt om de groep te informeren of het object verder kan worden gegroepeerd.
Als u deze functionaliteit wilt nabootsen, declareert het voorbeeld een openbare interface (IObjectControl
) met de bovengenoemde leden. Deze interface wordt vervolgens geïmplementeerd door serviceklassen die zijn bedoeld om contextspecifieke initialisatie te bieden. De IInstanceProvider implementatie moet worden aangepast om aan deze vereisten te voldoen. Telkens wanneer u een object krijgt door de GetInstance
methode aan te roepen, moet u controleren of het object wordt geïmplementeerd IObjectControl.
als dit het geval is, moet u de methode op de Activate
juiste manier aanroepen.
if (obj is IObjectControl)
{
((IObjectControl)obj).Activate();
}
Wanneer u een object naar de pool retourneert, is een controle vereist voor de CanBePooled
eigenschap voordat u het object weer toevoegt aan de pool.
if (instance is IObjectControl)
{
IObjectControl objectControl = (IObjectControl)instance;
objectControl.Deactivate();
if (objectControl.CanBePooled)
{
pool.Push(instance);
}
}
Omdat de serviceontwikkelaar kan bepalen of een object kan worden gegroepeerd, kan het aantal objecten in de pool op een bepaald moment onder de minimale grootte gaan. Daarom moet u controleren of het aantal objecten onder het minimumniveau is gegaan en de benodigde initialisatie in de opschoonprocedure uitvoert.
// Remove the surplus objects.
if (pool.Count > minPoolSize)
{
// Clean the surplus objects.
}
else if (pool.Count < minPoolSize)
{
// Reinitialize the missing objects.
while(pool.Count != minPoolSize)
{
pool.Push(CreateNewPoolObject());
}
}
Wanneer u het voorbeeld uitvoert, worden de bewerkingsaanvragen en -antwoorden weergegeven in zowel de service- als clientconsolevensters. Druk in elk consolevenster op Enter om de service en client af te sluiten.
Het voorbeeld instellen, compileren en uitvoeren
Zorg ervoor dat u de eenmalige installatieprocedure voor de Windows Communication Foundation-voorbeelden hebt uitgevoerd.
Volg de instructies in Het bouwen van de Windows Communication Foundation-voorbeelden om de oplossing te bouwen.
Als u het voorbeeld wilt uitvoeren in een configuratie met één of meerdere computers, volgt u de instructies in Het uitvoeren van de Windows Communication Foundation-voorbeelden.