Допустим есть wcf служба, которая хостится в win service.
Если пользователь решит вырубить сервис, то как мне грамотно завершить работу wcf службы?
Допустим, один юзер вызвал метод по перемещению файлов, другой юзер что-то делает с базой.
Если без логики завершить работу Win Service, то это приведет к необратимым последствиям.
Ответ
Можно попробовать при остановке Win Service сигналить в WCF Service с помощью CancellationToken о том, что Win Service собирается останавливаться. WCF Service внутри себя должен проверять состояние данного CancellationToken, и, если запрошена отмена, выдавать исключение для вновь запрашиваемых операций, а уже выполняющиеся, например, прерывать. Win Service должен дождаться завершения отмены активных операций выполняемых WCF Service. Для отслеживания этого в WCF Service можно, к примеру, использовать ManualResetEvent и счётчик активных операций.
Ниже примерная реализация (с достаточным числом упрощений).
Контракт:
[ServiceContract]
public interface IWCFService
{
[OperationContract]
string Echo(string str);
}
WCF Service:
public class WCFService : IWCFService
{
CancellationToken ctOperations;
public WCFService()
{
//у WinService берём CancellationToken остановки операций
ctOperations = MyService.GetOperationsCancellationToken();
}
public string Echo(string str)
{
//не выполняем новые операции, если началась остановка
if (ctOperations.IsCancellationRequested)
throw new Exception("Service stopping.");
try
{
//увеличиваем счётчик активных операций
IncActiveCnt();
//имитация деятельности
int i = 0;
while (i++ < 10)
{
ctOperations.ThrowIfCancellationRequested();
Thread.Sleep(500);
}
return "Echo " + str;
}
catch (OperationCanceledException)
{
throw new Exception("Service stopping.");
}
catch (Exception)
{
throw;
}
finally
{
//уменьшаем счётчик активных операций
DecActiveCnt();
}
}
static object lockObj = new object();
static int activeOperationCnt = 0;
static ManualResetEvent evtNoActiveOperations = new ManualResetEvent(true);
//свойство для проверки в WinService
static public ManualResetEvent NoActiveOperations { get { return evtNoActiveOperations; } }
private void DecActiveCnt()
{
lock (lockObj)
{
if (--activeOperationCnt == 0)
//сигналим, если нет активных операций
evtNoActiveOperations.Set();
}
}
private void IncActiveCnt()
{
lock (lockObj)
{
activeOperationCnt++;
//сбрасываем сигнал, если есть активные операции
evtNoActiveOperations.Reset();
}
}
}
Win Service (в данном примере не внешнее приложение, а он сам себе является клиентом WCF Service):
public class MyService : ServiceBase
{
static CancellationTokenSource ctsOperations = null;
static ServiceHost svcHost = null;
public MyService() { }
protected override void OnStart(string[] args)
{
//токен для остановки операций
ctsOperations = new CancellationTokenSource();
svcHost = new ServiceHost(typeof(WCFService));
svcHost.Open();
//запускаем клиента WCF Service
ThreadPool.QueueUserWorkItem(UseWCFService);
//ждём 13 сек.
Thread.Sleep(13000);
//теперь остановим Win Service
Stop();
}
protected override void OnStop()
{
//сигналим отмену операций
ctsOperations.Cancel();
int msecExtend = 3000;
RequestAdditionalTime(msecExtend);
//ждём завершение отмены операций
WCFService.NoActiveOperations.WaitOne(msecExtend);
svcHost.Close();
ctsOperations.Dispose();
}
public static CancellationToken GetOperationsCancellationToken()
{
return ctsOperations.Token;
}
private void UseWCFService(object state)
{
//имитируем клиента
Uri tcpUri = new Uri(@"http://localhost:8733/WCFService/");
EndpointAddress address = new EndpointAddress(tcpUri);
BasicHttpBinding binding = new BasicHttpBinding();
ChannelFactory
int i = 0;
while (!ctsOperations.IsCancellationRequested)
try
{
string echo = svc.Echo((++i).ToString());
Console.WriteLine(echo);
}
catch
{
Console.WriteLine("Error");
}
}
}
Комментариев нет:
Отправить комментарий