Поделиться через


Пользовательское время существования

В примере времени существования показано, как написать расширение Windows Communication Foundation (WCF) для предоставления пользовательских служб времени существования для общих экземпляров служб WCF.

Примечание.

Процедура настройки и инструкции по построению для данного примера приведены в конце этого раздела.

Общие входящие в систему

WCF предлагает несколько режимов встановки для экземпляров служб. Общий режим инстантирования, описанный в этой статье, предоставляет способ совместного использования экземпляра службы между несколькими каналами. Клиенты могут связаться с методом фабрики в службе и создать новый канал для запуска связи. В следующем фрагменте кода показано, как клиентское приложение создает новый канал для существующего экземпляра службы:

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

В отличие от других режимов создания экземпляров, режим создания общих экземпляров располагает уникальным способом освобождения экземпляров служб. По умолчанию, когда все каналы закрыты для InstanceContextсреды выполнения службы WCF, проверка, чтобы узнать, настроена PerCall ли служба InstanceContextMode илиPerSession, если да, освобождает экземпляр и утверждает ресурсы. Если используется пользовательская IInstanceContextProvider функция, WCF вызывает IsIdle метод реализации поставщика перед выпуском экземпляра. Если IsIdle возвращается true экземпляр, в противном случае IInstanceContextProvider реализация отвечает за уведомление Dispatcher о состоянии простоя с помощью метода обратного вызова. Это делается путем NotifyIdle вызова метода поставщика.

В этом примере показано, как можно отложить освобождение InstanceContext времени ожидания простоя в 20 секунд.

Расширение InstanceContext

В WCF InstanceContext связь между экземпляром службы и экземпляром Dispatcherслужбы. WCF позволяет расширить этот компонент среды выполнения, добавив новое состояние или поведение с помощью его расширяемого шаблона объекта. Шаблон расширяемого объекта используется в WCF для расширения существующих классов среды выполнения с новыми функциями или добавления новых функций состояния в объект. Предусмотрено три интерфейса в шаблоне расширяемого объекта: IExtensibleObject<T>, IExtension<T> и IExtensionCollection<T>.

Интерфейс IExtensibleObject<T> реализуется объектами для разрешения расширений, которые настраивают их функциональные возможности.

Интерфейс IExtension<T> реализуется объектами, которые могут быть расширениями классов типа T.

И наконец, IExtensionCollection<T> интерфейс — это коллекция реализаций IExtension<T> , которая позволяет получить реализацию IExtension<T> по их типу.

Таким образом, чтобы расширить InstanceContextинтерфейс, необходимо реализовать IExtension<T> интерфейс. В этом примере проекта CustomLeaseExtension класс содержит эту реализацию.

class CustomLeaseExtension : IExtension<InstanceContext>
{
}

У интерфейса IExtension<T> имеется два метода: Attach и Detach. Как видно по их именам, два этих метода вызываются, когда среда выполнения присоединяет и отсоединяет расширение экземпляра класса InstanceContext. В этом образце метод Attach используется для отслеживания объекта InstanceContext, который принадлежит текущему экземпляру расширения.

InstanceContext owner;

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

Кроме того, в расширение необходимо добавить требуемую реализацию, чтобы обеспечить поддержку продленного времени существования. ICustomLease Поэтому интерфейс объявляется с требуемыми методами и реализуется в CustomLeaseExtension классе.

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

class CustomLeaseExtension : IExtension<InstanceContext>, ICustomLease
{
}

При вызове IsIdleIInstanceContextProvider метода в реализации WCF этот вызов направляется в IsIdle метод.CustomLeaseExtension Затем проверка его частное состояние, чтобы узнать, CustomLeaseExtension неактивен ли InstanceContext он. Если он неактивен, возвращается true. В противном случае запускается таймер на указанное продленное время существования.

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

В событии таймера Elapsed функция обратного вызова в диспетчере вызывается для запуска другого цикла очистки.

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

При поступлении нового сообщения для экземпляра в состояние простоя невозможно обновить таймер выполнения.

Для перехвата вызовов метода IInstanceContextProvider и их перенаправления расширению IsIdle образец реализует CustomLeaseExtension. Реализация IInstanceContextProvider содержится в классе CustomLifetimeLease. Метод IsIdle вызывается, когда WCF собирался освободить экземпляр службы. Однако в коллекции ServiceBehavior IInstanceContextProvider существует только один экземпляр конкретной ISharedSessionInstance реализации. Это означает, что нет способа знатьInstanceContext, закрыт ли этот метод во время проверка IsIdle WCF. Поэтому в этом примере используется блокировка потока для сериализации запросов к методу IsIdle .

Внимание

Использовать блокировку потока не рекомендуется, поскольку сериализация может значительно снизить производительность приложения.

Поле частного члена используется в CustomLifetimeLease классе для отслеживания состояния простоя и возвращается методом IsIdle . IsIdle При каждом вызове isIdle метода поле возвращается и сбрасывается в false. Важно задать этому параметру значение false с тем, чтобы гарантировать вызов диспетчером метода NotifyIdle.

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

IInstanceContextProvider.IsIdle Если метод возвращаетсяfalse, диспетчер регистрирует функцию обратного вызова с помощью NotifyIdle метода. Этот метод получает ссылку на освобождаемый контекст InstanceContext. Поэтому пример кода может запрашивать ICustomLease расширение типа и проверка ICustomLease.IsIdle свойство в расширенном состоянии.

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

ICustomLease.IsIdle Прежде чем свойство проверка, необходимо задать свойство обратного вызова, так как это важно для CustomLeaseExtension уведомления диспетчера при его простои. Если ICustomLease.IsIdle возвращает значение true, то закрытому элементу isIdle в CustomLifetimeLease просто устанавливается значение true и вызывается метод обратного вызова. Так как код содержит блокировку, другие потоки не могут изменить значение этого закрытого члена. И при следующем вызове IInstanceContextProvider.IsIdleдиспетчера возвращается true и позволяет диспетчеру освободить экземпляр.

Завершив подготовительную работу для пользовательского расширения, его необходимо подключить к модели службы. Чтобы подключить CustomLeaseExtension реализацию к InstanceContext, WCF предоставляет IInstanceContextInitializer интерфейс для выполнения начальной загрузки InstanceContext. В этом образце класс CustomLeaseInitializer реализует этот интерфейс и добавляет экземпляр CustomLeaseExtension в коллекцию Extensions из единственной инициализации метода. Этот метод вызывается диспетчером при инициализации InstanceContext.

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

    //...

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

Наконец, IInstanceContextProvider реализация подключается к модели службы с помощью IServiceBehavior реализации. Эта реализация помещается в класс CustomLeaseTimeAttribute, кроме того, она является производной от базового класса Attribute для предоставления этого поведения в виде атрибута.

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

Это поведение можно добавить в класс образца службы, сопроводив его заметкой в вида атрибута CustomLeaseTime.

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

При запуске данного примера запросы и ответы операций отображаются в окнах консоли как службы, так и клиента. Нажмите клавишу ВВОД в каждом окне консоли, чтобы закрыть службу и клиент.

Настройка, сборка и выполнение образца

  1. Убедитесь, что вы выполнили процедуру одноразовой установки для примеров Windows Communication Foundation.

  2. Чтобы создать выпуск решения на языке C# или Visual Basic .NET, следуйте инструкциям в разделе Building the Windows Communication Foundation Samples.

  3. Чтобы запустить пример в конфигурации с одним или несколькими компьютерами, следуйте инструкциям в разделе "Примеры Windows Communication Foundation".