Пользовательские службы времени существования
Этот образец демонстрирует написание расширения Windows Communication Foundation (WCF) для предоставления пользовательских служб времени существования для экземпляров общих служб WCF.
Примечание |
---|
Процедура настройки и инструкции по построению для этого образца приведены в конце этого раздела. |
WCF предлагает несколько режимов создания экземпляров служб. Режим создания общих экземпляров, описанный в этом разделе, предоставляет способ совместного использования экземпляра службы несколькими каналами. Клиенты могут разрешать адрес конечной точки экземпляра локально или обращаться к методу производства в службе, чтобы получить адрес конечной точки работающего экземпляра. Получив адрес конечной точки, клиент может создать новый канал и начать обмен данными. Следующий фрагмент кода показывает, как клиентское приложение создает новый канал к существующему экземпляру службы.
// Create the first channel.
IEchoService proxy = channelFactory.CreateChannel();
// Resolve the instance.
EndpointAddress epa = ((IClientChannel)proxy).ResolveInstance();
// Create new channel factory with the endpoint address resolved by
// previous statement.
ChannelFactory<IEchoService> channelFactory2 =
new ChannelFactory<IEchoService>("echoservice",
epa);
// Create the second channel to the same instance.
IEchoService proxy2 = channelFactory2.CreateChannel();
В отличие от других режимов создания экземпляров, режим создания общих экземпляров располагает уникальным способом освобождения экземпляров служб. Когда все каналы для экземпляра закрыты, среда выполнения WCF службы запускает таймер. Если никто не установит соединение до истечения времени ожидания, WCF освободит экземпляр и вернет себе ресурсы. В рамках процедуры демонтажа перед освобождением экземпляра WCF вызывает метод IsIdle всех реализаций IShareableInstanceContextLifetime. Если все они возвратят значение true, экземпляр будет освобожден. В противном случае реализация IShareableInstanceContextLifetime отвечает за уведомление Dispatcher о состоянии бездействия с помощью метода обратного вызова.
По умолчанию значение времени ожидания состояния бездействия InstanceContext равно одной минуте. Однако в этом образце показано, как его можно продлить с помощью пользовательского расширения.
В WCF контекст InstanceContext является каналом между экземпляром службы и Dispatcher. WCF позволяет расширять этот компонент среды выполнения путем добавления нового состояния или поведения с помощью его расширяемого шаблона объекта. Шаблон расширяемого объекта используется в WCF для расширения существующих классов среды выполнения с помощью новых функциональных возможностей или добавления новых функций состояния к объекту. Предусмотрено три интерфейса в шаблоне расширяемого объекта: IExtensibleObject<T>, IExtension<T> и IExtensionCollection<T>.
Интерфейс IExtensibleObject<T> реализуется объектами для обеспечения расширений, которые настраивают их функциональность.
Интерфейс IExtension<T> реализуется объектами, которые могут быть расширениями классов типа T.
И наконец, интерфейс IExtensionCollection<T> является коллекцией IExtensions, которая позволяет получать IExtensions по их типу.
Поэтому, чтобы расширить контекст InstanceContext, требуется реализовать интерфейс IExtension. В данном образце проекта эту реализацию содержит класс CustomLeaseExtension
.
class CustomLeaseExtension : IExtension<InstanceContext>
{
}
У интерфейса IExtension имеется два метода: 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
{
}
Когда WCF вызывает метод IsIdle в реализации IShareableInstanceContextLifetime, этот вызов направляется методу 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)
{
idleTimer.Stop();
isIdle = true;
callback(owner);
}
При поступлении нового сообщения для экземпляра, перемещаемого в состояние бездействия, возобновить работающий таймер невозможно.
Для перехвата вызовов метода IsIdle и их перенаправления расширению CustomLeaseExtension
образец реализует IShareableInstanceContextLifetime. Реализация IShareableInstanceContextLifetime содержится в классе CustomLifetimeLease
. Метод IsIdle вызывается, когда WCF собирается освободить экземпляр службы. Однако в коллекции InstanceContextLifetimes ServiceBehavior имеется только один экземпляр конкретной реализации ISharedSessionInstance
. Это значит, что узнать о закрытии InstanceContext в тот момент, когда WCF проверяет метод IsIdle, невозможно. Поэтому этот образец использует блокировку потока для сериализации запросов в метод IsIdle.
Примечание |
---|
Использовать блокировку потока не рекомендуется, поскольку сериализация может значительно снизить производительность приложения. |
Для отслеживания значения IsIdle
в классе CustomLeaseExtension
используется переменная закрытого элемента. Каждый раз при получении значения IShareableInstanceContextLifetime закрытый элемент IsIdle
возвращается и сбрасывается в значение false. Важно задать этому параметру значение false с тем, чтобы гарантировать вызов диспетчером метода NotifyIdle.
public bool IsIdle
{
get
{
lock (thisLock)
{
bool idleCopy = isIdle;
isIdle = false;
return idleCopy;
}
}
}
Если свойство ISharedSessionLifetime.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
необходимо задать значение свойства Callback, поскольку оно требуется CustomLeaseExtension
для уведомления диспетчера при переходе в состояние бездействия. Если ICustomLease.IsIdle
возвращает значение true, то закрытому элементу isIdle
в CustomLifetimeLease
просто устанавливается значение true и вызывается метод обратного вызова. Поскольку код содержит блокировку, другие потоки не могут изменить значение этого закрытого элемента. При следующей проверке диспетчером ISharedSessionLifetime.IsIdle
возвращается значение true, при этом диспетчер может освободить экземпляр.
Завершив подготовительную работу для пользовательского расширения, его необходимо подключить к модели службы. Чтобы подключить реализацию CustomLeaseExtension
к контексту InstanceContext, WCF предоставляет интерфейс IInstanceContextInitializer для выполнения начальной загрузки InstanceContext. В этом образце класс CustomLeaseInitializer
реализует этот интерфейс и добавляет экземпляр CustomLeaseExtension
в коллекцию Extensions из единственной инициализации метода. Этот метод вызывается диспетчером при инициализации InstanceContext.
public void Initialize(InstanceContext instanceContext, Message message)
{
IExtension<InstanceContext> customLeaseExtension =
new CustomLeaseExtension(timeout);
instanceContext.Extensions.Add(customLeaseExtension);
}
Наконец, реализации IShareableInstanceContextLifetime и IInstanceContextInitializer подключаются к модели службы с помощью реализации IServiceBehavior. Эта реализация помещается в класс CustomLeaseTimeAttribute
, кроме того, она является производной от базового класса Attribute
для предоставления этого поведения в виде атрибута. В методе IServiceBehavior.ApplyBehavior
экземпляры реализаций IInstanceContextInitializer и IShareableInstanceContextLifetime добавляются в коллекции InstanceContextLifetimes и InstanceContextInitializers диспетчера System.ServiceModel.Dispatcher соответственно.
public void ApplyBehavior(ServiceDescription description,
ServiceHostBase serviceHostBase,
Collection<DispatchBehavior> behaviors,
Collection<BindingParameterCollection> parameters)
{
CustomLifetimeLease customLease = new CustomLifetimeLease();
CustomLeaseInitializer initializer =
new CustomLeaseInitializer(timeout);
foreach (DispatchBehavior dispatchBehavior in behaviors)
{
dispatchBehavior.InstanceContextLifetimes.Add(customLease);
dispatchBehavior.InstanceContextInitializers.Add(initializer);
}
}
Это поведение можно добавить в класс образца службы, сопроводив его заметкой в вида атрибута CustomLeaseTime
.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Shareable)]
[CustomLeaseTime(Timeout = 20000)]
public class EchoService : IEchoService
{
//…
}
При выполнении образца запросы и ответы операций отображаются в окнах консоли как службы, так и клиента. Нажмите клавишу ВВОД в каждом окне консоли, чтобы закрыть службу и клиент.
Убедитесь, что выполнены процедуры, описанные в разделе Процедура однократной настройки образцов Windows Communication Foundation.
Чтобы выполнить построение версии решения для языка C# или Visual Basic .NET, следуйте инструкциям раздела Построение образцов Windows Communication Foundation.
Чтобы выполнить образец на одном или нескольких компьютерах, следуйте инструкциям в разделе Running the Windows Communication Foundation Samples.
Примечание |
---|
Образцы уже могут быть установлены на компьютере. Перед продолжением проверьте следующий каталог (по умолчанию).
<диск_установки>:\WF_WCF_Samples
Если этот каталог не существует, перейдите на страницу Образцы Windows Communication Foundation (WCF) и Windows Workflow Foundation (WF) для .NET Framework 4, чтобы загрузить все образцы Windows Communication Foundation (WCF) и WF. Этот образец расположен в следующем каталоге.
<диск_установки>:\WF_WCF_Samples\WCF\Extensibility\Instancing\Lifetime
|