Udostępnij za pośrednictwem


Tworzenie wystąpienia inicjowania

Przykład inicjowania rozszerza przykład buforowania, definiując interfejs , IObjectControlktóry dostosowuje inicjowanie obiektu przez aktywowanie i dezaktywację. Klient wywołuje metody, które zwracają obiekt do puli i które nie zwracają obiektu do puli.

Uwaga

Procedura instalacji i instrukcje kompilacji dla tego przykładu znajdują się na końcu tego tematu.

Punkty rozszerzalności

Pierwszym krokiem tworzenia rozszerzenia programu Windows Communication Foundation (WCF) jest podjęcie decyzji o tym, czy punkt rozszerzalności ma być używany. W programie WCF termin EndpointDispatcher odnosi się do składnika czasu wykonywania odpowiedzialnego za konwertowanie komunikatów przychodzących na wywołania metody w usłudze użytkownika i konwertowanie wartości zwracanych z tej metody na komunikat wychodzący. Usługa WCF tworzy punkt końcowyDispatcher dla każdego punktu końcowego.

Funkcja EndpointDispatcher oferuje zakres punktu końcowego (dla wszystkich komunikatów odebranych lub wysłanych przez usługę EndpointDispatcher ) rozszerzalność przy użyciu klasy . Ta klasa umożliwia dostosowanie różnych właściwości kontrolujących zachowanie programu EndpointDispatcher. Ten przykład koncentruje się na InstanceProvider właściwości wskazującej obiekt, który udostępnia wystąpienia klasy usługi.

IInstanceProvider

W programie WCF program EndpointDispatcher tworzy wystąpienia klasy usługi przy użyciu dostawcy wystąpień, który implementuje IInstanceProvider interfejs. Ten interfejs ma tylko dwie metody:

  • GetInstance: Po nadejściu komunikatu dyspozytor wywołuje GetInstance metodę , aby utworzyć wystąpienie klasy usługi w celu przetworzenia komunikatu. Częstotliwość wywołań do tej metody jest określana InstanceContextMode przez właściwość . Na przykład jeśli InstanceContextMode właściwość jest ustawiona na InstanceContextMode.PerCall, zostanie utworzone nowe wystąpienie klasy usługi w celu przetworzenia każdego komunikatu, więc GetInstance jest wywoływany za każdym razem, gdy pojawi się komunikat.

  • ReleaseInstance: Po zakończeniu przetwarzania komunikatu wystąpienie usługi wywołuje metodę ReleaseInstance EndpointDispatcher. Podobnie jak w metodzie GetInstance , częstotliwość wywołań do tej metody jest określana przez InstanceContextMode właściwość .

Pula obiektów

Klasa ObjectPoolInstanceProvider zawiera implementację puli obiektów. Ta klasa implementuje IInstanceProvider interfejs do interakcji z warstwą modelu usługi. Gdy program EndpointDispatcher wywołuje metodę GetInstance , zamiast tworzyć nowe wystąpienie, implementacja niestandardowa wyszukuje istniejący obiekt w puli w pamięci. Jeśli jest dostępny, zostanie zwrócony. W przeciwnym razie sprawdza, ObjectPoolInstanceProvider czy ActiveObjectsCount właściwość (liczba obiektów zwróconych z puli) osiągnęła maksymalny rozmiar puli. Jeśli nie, zostanie utworzone nowe wystąpienie i zwrócone do obiektu wywołującego, a ActiveObjectsCount następnie zostanie przyrostowane. W przeciwnym razie żądanie utworzenia obiektu jest kolejkowane przez skonfigurowany okres czasu. Implementacja dla elementu GetObjectFromThePool jest pokazana w poniższym przykładowym kodzie.

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"));
}

Implementacja niestandardowa ReleaseInstance dodaje wydane wystąpienie z powrotem do puli i dekrementuje ActiveObjectsCount wartość. Program EndpointDispatcher może wywoływać te metody z różnych wątków i dlatego wymagany jest zsynchronizowany dostęp do składowych na poziomie klasy w ObjectPoolInstanceProvider klasie.

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);
}

Metoda ReleaseInstance udostępnia funkcję inicjowania czyszczenia . Zwykle pula utrzymuje minimalną liczbę obiektów przez okres istnienia puli. Mogą jednak istnieć okresy nadmiernego użycia, które wymagają utworzenia dodatkowych obiektów w puli w celu osiągnięcia maksymalnego limitu określonego w konfiguracji. Ostatecznie, gdy pula stanie się mniej aktywna, te obiekty nadwyżkowe mogą stać się dodatkowym obciążeniem. W związku z tym, gdy activeObjectsCount czasomierz bezczynności osiągnie zero, wyzwala i wykonuje cykl oczyszczania.

if (activeObjectsCount == 0)
{
    idleTimer.Start();
}

Rozszerzenia warstwy ServiceModel są podłączane przy użyciu następujących zachowań:

  • Zachowania usługi: umożliwiają one dostosowanie całego środowiska uruchomieniowego usługi.

  • Zachowania punktów końcowych: umożliwiają one dostosowanie określonego punktu końcowego usługi, w tym endpointDispatcher.

  • Zachowania kontraktu: umożliwiają one dostosowanie ClientRuntime klas lub DispatchRuntime odpowiednio na kliencie lub w usłudze.

  • Zachowania operacji: umożliwiają one dostosowanie ClientOperation klas lub DispatchOperation odpowiednio na kliencie lub w usłudze.

W celu rozszerzenia buforowania obiektów można utworzyć zachowanie punktu końcowego lub zachowanie usługi. W tym przykładzie używamy zachowania usługi, które stosuje możliwość buforowania obiektów do każdego punktu końcowego usługi. Zachowania usługi są tworzone przez zaimplementowanie interfejsu IServiceBehavior . Istnieje kilka sposobów informowania modelu ServiceModel o niestandardowych zachowaniach:

  • Używanie atrybutu niestandardowego.

  • Imperatywnie dodanie jej do kolekcji zachowań opisu usługi.

  • Rozszerzanie pliku konfiguracji.

W tym przykładzie użyto atrybutu niestandardowego. Po utworzeniu ServiceHost obiektu sprawdza atrybuty używane w definicji typu usługi i dodaje dostępne zachowania do kolekcji zachowań opisu usługi.

Interfejs IServiceBehavior ma trzy metody: AddBindingParameters, Validate, i .ApplyDispatchBehavior Metody te są wywoływane przez usługę WCF podczas inicjowania ServiceHost . IServiceBehavior.Validate jest wywoływana jako pierwsza; umożliwia inspekcję usługi pod kątem niespójności. IServiceBehavior.AddBindingParameters jest wywoływana dalej; Ta metoda jest wymagana tylko w bardzo zaawansowanych scenariuszach. IServiceBehavior.ApplyDispatchBehavior jest wywoływany jako ostatni i jest odpowiedzialny za konfigurowanie środowiska uruchomieniowego. Następujące parametry są przekazywane do IServiceBehavior.ApplyDispatchBehaviorelementu :

  • Description: Ten parametr zawiera opis usługi dla całej usługi. Może to służyć do sprawdzania danych opisu dotyczących punktów końcowych, kontraktów, powiązań i innych danych skojarzonych z usługą.

  • ServiceHostBase: ten parametr udostępnia ServiceHostBase aktualnie inicjowany parametr.

W implementacji niestandardowej IServiceBehavior nowe wystąpienie ObjectPoolInstanceProvider klasy jest tworzone i przypisywane do InstanceProvider właściwości w każdym EndpointDispatcher dołączonym do klasy ServiceHostBase.

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;
                 }
             }
         }
     }
}

Oprócz IServiceBehavior implementacji ObjectPoolingAttribute klasa ma kilka elementów członkowskich, aby dostosować pulę obiektów przy użyciu argumentów atrybutów. Te elementy członkowskie to MaxSize, Enabled MinSizei CreationTimeout, aby były zgodne z zestawem funkcji buforowania obiektów udostępnianym przez usługi .NET Enterprise Services.

Zachowanie buforowania obiektów można teraz dodać do usługi WCF, dodając adnotację do implementacji usługi przy użyciu nowo utworzonego atrybutu niestandardowego ObjectPooling .

[ObjectPooling(MaxSize=1024, MinSize=10, CreationTimeout=30000]
public class PoolService : IPoolService
{
  // …
}

Hakowanie aktywacji i dezaktywacji

Głównym celem buforowania obiektów jest zoptymalizowanie krótkotrwałych obiektów przy stosunkowo drogim tworzeniu i inicjowaniu. W związku z tym może to dać dramatyczny wzrost wydajności aplikacji, jeśli zostanie prawidłowo użyty. Ponieważ obiekt jest zwracany z puli, konstruktor jest wywoływany tylko raz. Jednak niektóre aplikacje wymagają pewnego poziomu kontroli, dzięki czemu mogą inicjować i czyścić zasoby używane w jednym kontekście. Na przykład obiekt używany dla zestawu obliczeń może zresetować swoje pola prywatne przed przetworzeniem następnego obliczenia. Usługi przedsiębiorstwa włączyły tego rodzaju inicjowanie specyficzne dla kontekstu, umożliwiając deweloperowi obiektów zastąpienie Activate metod i Deactivate metod z klasy bazowej ServicedComponent .

Pula obiektów wywołuje metodę Activate tuż przed zwróceniem obiektu z puli. Deactivate jest wywoływany, gdy obiekt powraca do puli. Klasa ServicedComponent bazowa boolean ma również właściwość o nazwie CanBePooled, która może służyć do powiadamiania puli, czy obiekt można dalej pulować.

Aby naśladować tę funkcję, przykład deklaruje interfejs publiczny (IObjectControl), który ma wyżej wymienione elementy członkowskie. Ten interfejs jest następnie implementowany przez klasy usług przeznaczone do zapewnienia inicjowania specyficznego kontekstu. Aby IInstanceProvider spełnić te wymagania, należy zmodyfikować implementację. Teraz za każdym razem, gdy obiekt jest wywoływany przez wywołanie GetInstance metody, należy sprawdzić, czy obiekt implementuje IObjectControl. polecenie Jeśli tak, należy odpowiednio wywołać Activate metodę.

if (obj is IObjectControl)
{
    ((IObjectControl)obj).Activate();
}

Podczas zwracania obiektu do puli wymagane CanBePooled jest sprawdzenie właściwości przed dodaniem obiektu z powrotem do puli.

if (instance is IObjectControl)
{
    IObjectControl objectControl = (IObjectControl)instance;
    objectControl.Deactivate();
    if (objectControl.CanBePooled)
    {
       pool.Push(instance);
    }
}

Ponieważ deweloper usługi może zdecydować, czy obiekt może być w puli, liczba obiektów w puli w danym momencie może być niższa od minimalnego rozmiaru. W związku z tym należy sprawdzić, czy liczba obiektów przekroczyła minimalny poziom i wykonać niezbędną inicjację w procedurze czyszczenia.

// 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());
  }
}

Po uruchomieniu przykładu żądania operacji i odpowiedzi są wyświetlane w oknach konsoli usługi i klienta. Naciśnij Enter w każdym oknie konsoli, aby zamknąć usługę i klienta.

Aby skonfigurować, skompilować i uruchomić przykład

  1. Upewnij się, że wykonano procedurę instalacji jednorazowej dla przykładów programu Windows Communication Foundation.

  2. 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).

  3. Aby uruchomić przykład w konfiguracji pojedynczej lub między maszynami, postępuj zgodnie z instrukcjami w temacie Uruchamianie przykładów programu Windows Communication Foundation.