Udostępnij za pośrednictwem


Okres istnienia niestandardowy

W przykładzie Lifetime pokazano, jak napisać rozszerzenie programu Windows Communication Foundation (WCF) w celu zapewnienia niestandardowych usług okresu istnienia dla udostępnionych wystąpień usługi WCF.

Uwaga

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

Udostępnianie instancingu

Program WCF oferuje kilka trybów stancingu dla wystąpień usługi. Tryb udostępniania instancingu opisany w tym artykule umożliwia udostępnianie wystąpienia usługi między wieloma kanałami. Klienci mogą skontaktować się z metodą fabryki w usłudze i utworzyć nowy kanał w celu rozpoczęcia komunikacji. Poniższy fragment kodu pokazuje, jak aplikacja kliencka tworzy nowy kanał do istniejącego wystąpienia usługi:

// Create a header for the shared instance id
MessageHeader shareableInstanceContextHeader = MessageHeader.CreateHeader(
        CustomHeader.HeaderName,
        CustomHeader.HeaderNamespace,
        Guid.NewGuid().ToString());

// Create the channel factory
ChannelFactory<IEchoService> channelFactory =
    new ChannelFactory<IEchoService>("echoservice");

// Create the first channel
IEchoService proxy = channelFactory.CreateChannel();

// Call an operation to create shared service instance
using (new OperationContextScope((IClientChannel)proxy))
{
    OperationContext.Current.OutgoingMessageHeaders.Add(shareableInstanceContextHeader);
    Console.WriteLine("Service returned: " + proxy.Echo("Apple"));
}

((IChannel)proxy).Close();

// Create the second channel
IEchoService proxy2 = channelFactory.CreateChannel();

// Call an operation using the same header that will reuse the shared service instance
using (new OperationContextScope((IClientChannel)proxy2))
{
    OperationContext.Current.OutgoingMessageHeaders.Add(shareableInstanceContextHeader);
    Console.WriteLine("Service returned: " + proxy2.Echo("Apple"));
}

W przeciwieństwie do innych trybów stancing, udostępniony tryb stancing ma unikatowy sposób zwalniania wystąpień usługi. Domyślnie, gdy wszystkie kanały są zamykane dla InstanceContextprogramu , środowisko uruchomieniowe usługi WCF sprawdza, czy usługa InstanceContextMode jest skonfigurowana na PerCall wartość lub PerSession, a jeśli tak, zwalnia wystąpienie i oświadczenia zasobów. Jeśli jest używany niestandardowy IInstanceContextProvider , program WCF wywołuje IsIdle metodę implementacji dostawcy przed udostępnieniem wystąpienia. Jeśli IsIdle zwraca true wystąpienie jest zwalniane, w przeciwnym razie IInstanceContextProvider implementacja jest odpowiedzialna za powiadamianie Dispatcher o stanie bezczynności przy użyciu metody wywołania zwrotnego. Odbywa się to przez wywołanie NotifyIdle metody dostawcy.

W tym przykładzie pokazano, jak można opóźnić zwolnienie InstanceContext elementu z limitem czasu bezczynności przez 20 sekund.

Rozszerzanie obiektu InstanceContext

W programie WCF InstanceContext jest połączeniem między wystąpieniem usługi a elementem Dispatcher. Program WCF umożliwia rozszerzenie tego składnika środowiska uruchomieniowego przez dodanie nowego stanu lub zachowania przy użyciu rozszerzalnego wzorca obiektu. Rozszerzalny wzorzec obiektu jest używany w programie WCF do rozszerzania istniejących klas środowiska uruchomieniowego o nowe funkcje lub dodawania nowych funkcji stanu do obiektu. Istnieją trzy interfejsy w rozszerzalnym wzorcu obiektu: IExtensibleObject<T>, IExtension<T>i IExtensionCollection<T>.

Interfejs IExtensibleObject<T> jest implementowany przez obiekty, aby umożliwić rozszerzenia, które dostosują ich funkcjonalność.

Interfejs IExtension<T> jest implementowany przez obiekty, które mogą być rozszerzeniami klas typu T.

I wreszcie, interfejs jest kolekcją IExtension<T> implementacji, IExtensionCollection<T> która umożliwia pobieranie implementacji IExtension<T> według ich typu.

W związku z tym, aby rozszerzyć element InstanceContext, należy zaimplementować IExtension<T> interfejs. W tym przykładowym projekcie CustomLeaseExtension klasa zawiera tę implementację.

class CustomLeaseExtension : IExtension<InstanceContext>
{
}

Interfejs IExtension<T> ma dwie metody Attach i Detach. Jak implikują ich nazwy, te dwie metody są wywoływane, gdy środowisko uruchomieniowe dołącza i odłącza rozszerzenie do wystąpienia InstanceContext klasy. W tym przykładzie Attach metoda służy do śledzenia InstanceContext obiektu należącego do bieżącego wystąpienia rozszerzenia.

InstanceContext owner;

public void Attach(InstanceContext owner)
{
    this.owner = owner;
}

Ponadto należy dodać niezbędną implementację do rozszerzenia, aby zapewnić obsługę rozszerzonego okresu istnienia. ICustomLease W związku z tym interfejs jest deklarowany przy użyciu żądanych metod i jest implementowany w CustomLeaseExtension klasie .

interface ICustomLease
{
    bool IsIdle { get; }
    InstanceContextIdleCallback Callback { get; set; }
}

class CustomLeaseExtension : IExtension<InstanceContext>, ICustomLease
{
}

Gdy program WCF wywołuje metodę IsIdle w implementacjiIInstanceContextProvider, to wywołanie jest kierowane do IsIdle metody .CustomLeaseExtension Następnie funkcja CustomLeaseExtension sprawdza stan prywatny, aby sprawdzić, czy InstanceContext stan jest bezczynny. Jeśli jest bezczynny, zwraca wartość true. W przeciwnym razie uruchamia czasomierz dla określonej ilości rozszerzonego okresu istnienia.

public bool IsIdle
{
  get
  {
    lock (thisLock)
    {
      if (isIdle)
      {
        return true;
      }
      else
      {
        StartTimer();
        return false;
      }
    }
  }
}

W zdarzeniu czasomierza Elapsed funkcja wywołania zwrotnego w dyspozytorze jest wywoływana w celu uruchomienia innego cyklu oczyszczania.

void idleTimer_Elapsed(object sender, ElapsedEventArgs args)
{
    lock (thisLock)
    {
        StopTimer();
        isIdle = true;
        Utility.WriteMessageToConsole(
            ResourceHelper.GetString("MsgLeaseExpired"));
        callback(owner);
    }
}

Nie ma możliwości odnowienia czasomierza uruchomionego po nadejściu nowego komunikatu dla wystąpienia przeniesionego do stanu bezczynności.

Przykład implementuje przechwytywanie IInstanceContextProvider wywołań IsIdle metody i kierowanie ich do CustomLeaseExtensionmetody . Implementacja jest zawarta IInstanceContextProvider w CustomLifetimeLease klasie . Metoda IsIdle jest wywoływana, gdy program WCF ma zwolnić wystąpienie usługi. Jednak w kolekcji ServiceBehavior IInstanceContextProvider istnieje tylko jedno wystąpienie określonej ISharedSessionInstance implementacji. Oznacza to, że nie ma możliwości sprawdzenia, czy InstanceContext element jest zamknięty w czasie sprawdzania metody przez usługę IsIdle WCF. W związku z tym w tym przykładzie użyto blokowania wątków w celu serializacji żądań do IsIdle metody .

Ważne

Używanie blokowania wątków nie jest zalecanym podejściem, ponieważ serializacja może poważnie wpłynąć na wydajność aplikacji.

Prywatne pole składowe jest używane w CustomLifetimeLease klasie do śledzenia stanu bezczynności i jest zwracane przez metodę IsIdle . Za każdym razem, gdy metoda jest wywoływana IsIdle , isIdle pole jest zwracane i resetowane do false. Należy ustawić tę wartość false na , aby upewnić się, że dyspozytor wywołuje metodę NotifyIdle .

public bool IsIdle(InstanceContext instanceContext)
{
    get
    {
        lock (thisLock)
        {
            //...
            bool idleCopy = isIdle;
            isIdle = false;
            return idleCopy;
        }
    }
}

IInstanceContextProvider.IsIdle Jeśli metoda zwróci falsemetodę , dyspozytor rejestruje funkcję wywołania zwrotnego przy użyciu NotifyIdle metody . Ta metoda odbiera odwołanie do InstanceContext zwalnianego. W związku z tym przykładowy kod może wykonywać zapytania dotyczące ICustomLease rozszerzenia typu i sprawdzać ICustomLease.IsIdle właściwość w stanie rozszerzonym.

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

Przed sprawdzeniem ICustomLease.IsIdle właściwości należy ustawić właściwość Wywołanie zwrotne, ponieważ jest to niezbędne do CustomLeaseExtension powiadamiania dyspozytora, gdy stanie się bezczynny. Jeśli ICustomLease.IsIdle zwraca truewartość isIdle , prywatny element członkowski jest po prostu ustawiony CustomLifetimeLease na true wartość i wywołuje metodę wywołania zwrotnego. Ponieważ kod przechowuje blokadę, inne wątki nie mogą zmieniać wartości tego prywatnego elementu członkowskiego. A następnym razem, gdy dyspozytor wywołuje metodę IInstanceContextProvider.IsIdle, zwraca true i pozwala usłudze Dispatcher zwolnić wystąpienie.

Po zakończeniu prac związanych z rozszerzeniem niestandardowym należy podłączyć go do modelu usługi. Aby podłączyć implementację CustomLeaseExtension do InstanceContextprogramu , program WCF udostępnia IInstanceContextInitializer interfejs umożliwiający wykonanie rozruchu InstanceContextelementu . W przykładzie CustomLeaseInitializer klasa implementuje ten interfejs i dodaje wystąpienie CustomLeaseExtension do Extensions kolekcji z jedynej inicjalizacji metody. Ta metoda jest wywoływana przez dyspozytor podczas inicjowania metody InstanceContext.

public void InitializeInstanceContext(InstanceContext instanceContext,
    System.ServiceModel.Channels.Message message, IContextChannel channel)

    //...

    IExtension<InstanceContext> customLeaseExtension =
        new CustomLeaseExtension(timeout, headerId);
    instanceContext.Extensions.Add(customLeaseExtension);
}

Na koniec implementacja IInstanceContextProvider jest podłączona do modelu usługi przy użyciu implementacji IServiceBehavior . Ta implementacja jest umieszczana w klasie, a także pochodzi z klasy bazowej CustomLeaseTimeAttributeAttribute , aby uwidocznić to zachowanie jako atrybut.

public void ApplyDispatchBehavior(ServiceDescription description,
           ServiceHostBase serviceHostBase)
{
    CustomLifetimeLease customLease = new CustomLifetimeLease(timeout);

    foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
    {
        ChannelDispatcher cd = cdb as ChannelDispatcher;

        if (cd != null)
        {
            foreach (EndpointDispatcher ed in cd.Endpoints)
            {
                ed.DispatchRuntime.InstanceContextProvider = customLease;
            }
        }
    }
}

To zachowanie można dodać do przykładowej klasy usługi, dodając do niej adnotacje za pomocą atrybutu CustomLeaseTime .

[CustomLeaseTime(Timeout = 20000)]
public class EchoService : IEchoService
{
  //…
}

Po uruchomieniu przykładu żądania operacji i odpowiedzi są wyświetlane w oknach konsoli usługi i klienta. Naciśnij klawisz 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ć wersję rozwiązania w języku C# lub Visual Basic .NET, 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.