Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Ukázka sdružování ukazuje, jak rozšířit Windows Communication Foundation (WCF) na podporu sdružování objektů. Ukázka ukazuje, jak vytvořit atribut, který je syntakticky a sémanticky podobný ObjectPoolingAttribute funkcím atributů podnikových služeb. Sdružování objektů může výrazně zvýšit výkon aplikace. Pokud se však nepoužívá správně, může mít opačný účinek. Sdružování objektů pomáhá snížit režii opětovného vytváření často používaných objektů, které vyžadují rozsáhlou inicializaci. Pokud však volání metody na objekt ve fondu zabere poměrně dlouho, zařadí se do fronty další požadavky, jakmile je dosaženo maximální velikosti fondu. Proto se může nepodařit obsloužit některé požadavky na vytvoření objektu vyvoláním výjimky časového limitu.
Poznámka:
Postup nastavení a pokyny k sestavení pro tuto ukázku najdete na konci tohoto tématu.
Prvním krokem při vytváření rozšíření WCF je rozhodnutí o bodu rozšiřitelnosti, který se má použít.
Ve WCF výraz dispatcher odkazuje na komponentu modulu runtime zodpovědnou za převod příchozích zpráv na volání metod ve službě uživatele a k převodu vrácených hodnot z této metody na odchozí zprávu. Služba WCF vytvoří dispečer pro každý koncový bod. Klient WCF musí použít správce, pokud je kontrakt přidružený k tomuto klientovi duplexní kontrakt.
Dispečeři kanálů a koncových bodů nabízejí rozšiřitelnost na úrovni kanálu a kontraktu tím, že zveřejňují různé vlastnosti, které řídí chování dispečera. Tato DispatchRuntime vlastnost také umožňuje kontrolovat, upravovat nebo přizpůsobovat proces odesílání. Tato ukázka se zaměřuje na InstanceProvider vlastnost, která odkazuje na objekt, který poskytuje instance třídy služby.
Poskytovatel instance (IInstanceProvider)
Ve WCF dispečer vytvoří instance třídy služby pomocí InstanceProvider, který implementuje rozhraní IInstanceProvider. Toto rozhraní má tři metody:
GetInstance(InstanceContext, Message): Když zpráva dorazí Dispatcher volá metodu GetInstance(InstanceContext, Message) k vytvoření instance třídy služby pro zpracování zprávy. Frekvence volání této metody je určena InstanceContextMode vlastností. Pokud je například u InstanceContextMode vlastnosti nastavena PerCall, je vytvořena nová instance třídy služby ke zpracování každé doručené zprávy, tedy GetInstance(InstanceContext, Message) je volána při každém příchodu zprávy.
GetInstance(InstanceContext): Toto je identické s předchozí metodou, s výjimkou toho, že se vyvolá, pokud neexistuje argument Message.
ReleaseInstance(InstanceContext, Object): Když uplynula životnost instance služby, dispatcher volá metodu ReleaseInstance(InstanceContext, Object) . Stejně jako u GetInstance(InstanceContext, Message) metody je frekvence volání této metody určena InstanceContextMode vlastností.
Fond objektů
Vlastní IInstanceProvider implementace poskytuje požadovanou sémantiku sdružování objektů pro službu. Tato ukázka proto obsahuje typ ObjectPoolingInstanceProvider, který zajišťuje vlastní implementaci IInstanceProvider pro sdružování. Když Dispatcher zavolá metodu GetInstance(InstanceContext, Message), místo vytvoření nové instance vlastní implementace hledá existující objekt v paměťovém fondu. Pokud je k dispozici, vrátí se. V opačném případě se vytvoří nový objekt. Implementace je GetInstance znázorněna v následujícím ukázkovém kódu.
object IInstanceProvider.GetInstance(InstanceContext instanceContext, Message message)
{
object obj = null;
lock (poolLock)
{
if (pool.Count > 0)
{
obj = pool.Pop();
}
else
{
obj = CreateNewPoolObject();
}
activeObjectsCount++;
}
WritePoolMessage(ResourceHelper.GetString("MsgNewObject"));
idleTimer.Stop();
return obj;
}
Vlastní ReleaseInstance implementace přidá uvolněnou instanci zpět do fondu a sníží ActiveObjectsCount hodnotu. Tyto Dispatcher metody lze volat z různých vláken, a proto je vyžadován synchronizovaný přístup k členům ObjectPoolingInstanceProvider na úrovni třídy.
void IInstanceProvider.ReleaseInstance(InstanceContext instanceContext, object instance)
{
lock (poolLock)
{
pool.Push(instance);
activeObjectsCount--;
WritePoolMessage(
ResourceHelper.GetString("MsgObjectPooled"));
// When the service goes completely idle (no requests
// are being processed), the idle timer is started
if (activeObjectsCount == 0)
idleTimer.Start();
}
}
Metoda ReleaseInstance poskytuje funkci "vyčištění inicializace". Fond obvykle udržuje minimální počet objektů po dobu životnosti fondu. Může však existovat období nadměrného využití, která vyžadují vytvoření dalších objektů ve fondu, aby dosáhla maximálního limitu zadaného v konfiguraci. Nakonec, když se fond stane méně aktivním, mohou se tyto nadbytečné objekty stát zbytečnou přítěží. Pokud activeObjectsCount tedy dosáhne nuly, spustí se časovač nečinnosti, který aktivuje a provede cyklus čištění.
Přidání chování
Rozšíření dispečerské vrstvy se připojují pomocí následujících postupů:
Chování služeb. To umožňuje přizpůsobení celého běhového prostředí služby.
Chování koncových bodů To umožňuje přizpůsobení koncových bodů služby, konkrétně kanálu a dispečeru koncových bodů.
Chování smluv To umožňuje přizpůsobení tříd ClientRuntime a DispatchRuntime zvlášť pro klienta a službu.
Pro účely rozšíření sdružování objektů je nutné vytvořit chování služby. Chování služby se vytváří implementací IServiceBehavior rozhraní. Existuje několik způsobů, jak model služby seznámit s vlastními chováními:
Použití vlastního atributu
Imperativním přidáním do kolekce chování popisu služby.
Rozšíření konfiguračního souboru
Tato ukázka používá vlastní atribut. Při vytvoření ServiceHost prozkoumá atributy použité v definici typu služby a přidá dostupná chování do kolekce chování popisu služby.
IServiceBehavior Rozhraní má v něm tři metody -- Validate, AddBindingParametersa ApplyDispatchBehavior. Metoda Validate se používá k zajištění, aby bylo chování aplikováno na službu. V této ukázce implementace zajišťuje, že není služba nakonfigurována s Single. Metoda AddBindingParameters se používá ke konfiguraci vazeb služby. V tomto scénáři se nevyžaduje. Slouží ApplyDispatchBehavior ke konfiguraci dispečerů služby. Tato metoda je volána WCF, když je ServiceHost inicializováno. Do této metody se předají následující parametry:
Description: Tento argument poskytuje popis služby pro celou službu. Můžete ho použít ke kontrole popisových dat o koncových bodech, kontraktech, vazbách a dalších datech služby.ServiceHostBase: Tento argument poskytuje ServiceHostBase aktuálně inicializovaný.
Ve vlastní IServiceBehavior implementaci je vytvořena nová instance ObjectPoolingInstanceProvider a přiřazena k vlastnosti InstanceProvider v každé DispatchRuntime v ServiceHostBase.
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
{
// Create an instance of the ObjectPoolInstanceProvider.
ObjectPoolingInstanceProvider instanceProvider = new
ObjectPoolingInstanceProvider(description.ServiceType,
minPoolSize);
// Forward the call if we created a ServiceThrottlingBehavior.
if (this.throttlingBehavior != null)
{
((IServiceBehavior)this.throttlingBehavior).ApplyDispatchBehavior(description, serviceHostBase);
}
// In case there was already a ServiceThrottlingBehavior
// (this.throttlingBehavior==null), it should have initialized
// a single ServiceThrottle on all ChannelDispatchers.
// As we loop through the ChannelDispatchers, we verify that
// and modify the ServiceThrottle to guard MaxPoolSize.
ServiceThrottle throttle = null;
foreach (ChannelDispatcherBase cdb in
serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = cdb as ChannelDispatcher;
if (cd != null)
{
// Make sure there is exactly one throttle used by all
// endpoints. If there were others, we could not enforce
// MaxPoolSize.
if ((this.throttlingBehavior == null) &&
(this.maxPoolSize != Int32.MaxValue))
{
throttle ??= cd.ServiceThrottle;
if (cd.ServiceThrottle == null)
{
throw new
InvalidOperationException(ResourceHelper.GetString("ExNullThrottle"));
}
if (throttle != cd.ServiceThrottle)
{
throw new InvalidOperationException(ResourceHelper.GetString("ExDifferentThrottle"));
}
}
foreach (EndpointDispatcher ed in cd.Endpoints)
{
// Assign it to DispatchBehavior in each endpoint.
ed.DispatchRuntime.InstanceProvider =
instanceProvider;
}
}
}
// Set the MaxConcurrentInstances to limit the number of items
// that will ever be requested from the pool.
if ((throttle != null) && (throttle.MaxConcurrentInstances >
this.maxPoolSize))
{
throttle.MaxConcurrentInstances = this.maxPoolSize;
}
}
Kromě IServiceBehavior implementace ObjectPoolingAttribute třída má několik členů pro přizpůsobení fondu objektů pomocí argumentů atributu. Mezi tyto členy patří MaxPoolSize, MinPoolSizea CreationTimeout, aby odpovídaly sadě funkcí sdružování objektů poskytované službami .NET Enterprise Services.
Chování při sdružování objektů je teď možné přidat do služby WCF přidáním poznámek k implementaci služby pomocí nově vytvořeného vlastního ObjectPooling atributu.
[ObjectPooling(MaxPoolSize=1024, MinPoolSize=10, CreationTimeout=30000)]
public class PoolService : IPoolService
{
// …
}
Spustit ukázkový kód
Ukázka ukazuje výhody výkonu, které je možné získat pomocí sdružování objektů v určitých scénářích.
Aplikace služby implementuje dvě služby – WorkService a ObjectPooledWorkService. Obě služby sdílejí stejnou implementaci – obě vyžadují nákladné inicializace a pak zveřejňují metodu DoWork() , která je relativně levná. Jediným rozdílem je, že ObjectPooledWorkService má nakonfigurované sdružování objektů:
[ObjectPooling(MinPoolSize = 0, MaxPoolSize = 5)]
public class ObjectPooledWorkService : IDoWork
{
public ObjectPooledWorkService()
{
Thread.Sleep(5000);
ColorConsole.WriteLine(ConsoleColor.Blue, "ObjectPooledWorkService instance created.");
}
public void DoWork()
{
ColorConsole.WriteLine(ConsoleColor.Blue, "ObjectPooledWorkService.GetData() completed.");
}
}
Když spustíte klienta, bude volat WorkService 5krát. Následně změří čas volání ObjectPooledWorkService 5krát. Zobrazí se rozdíl v čase:
Press <ENTER> to start the client.
Calling WorkService:
1 - DoWork() Done
2 - DoWork() Done
3 - DoWork() Done
4 - DoWork() Done
5 - DoWork() Done
Calling WorkService took: 26722 ms.
Calling ObjectPooledWorkService:
1 - DoWork() Done
2 - DoWork() Done
3 - DoWork() Done
4 - DoWork() Done
5 - DoWork() Done
Calling ObjectPooledWorkService took: 5323 ms.
Press <ENTER> to exit.
Poznámka:
Když je klient poprvé spuštěn, zdá se, že obě služby trvají přibližně stejnou dobu. Pokud ukázku znovu spustíte, uvidíte, že ObjectPooledWorkService se vrací výrazně rychleji, protože instance tohoto objektu už ve fondu existuje.
Jak nastavit, sestavit a spustit ukázku
Ujistěte se, že jste provedli instalační proceduru One-Time pro ukázky Windows Communication Foundation.
Pro sestavení řešení postupujte podle pokynů v Sestavení ukázek Windows Communication Foundation.
Pokud chcete spustit ukázku v konfiguraci pro jeden počítač nebo pro více počítačů, postupujte podle pokynů v Spuštění ukázek Windows Communication Foundation.
Poznámka:
Pokud použijete Svcutil.exe k opětovnému vygenerování konfigurace pro tuto ukázku, nezapomeňte upravit název koncového bodu v konfiguraci klienta tak, aby odpovídal kódu klienta.