Проблема связи между AppDomain
Я занимаюсь разработкой службы Windows на С#.
При запуске этой службы предоставляется набор путей файла конфигурации. Для каждого из этих файлов служба будет разворачивать AppDomain
с использованием файла в качестве ConfigurationFile
и папки этого файла как ApplicationBase
. Каждая папка будет иметь папку "bin", которая устанавливается как PrivateBinPath
.
В папке "bin" в этих папках содержится небольшая сборка, которая совместно используется службой, эта сборка содержит интерфейс IServiceHost
. Также известно имя типа и имя сборки класса, реализующего интерфейс IServiceHost
.
Весь метод CreateServiceHost
выглядит следующим образом: -
public static IServiceHost CreateServiceHost(string configPath, string entryAssembly, string entryType)
{
IServiceHost host;
AppDomainSetup setupInfo = new AppDomainSetup();
setupInfo.ApplicationBase = Path.GetDirectoryName(configPath);
setupInfo.PrivateBinPath = Path.Combine(setupInfo.ApplicationBase, "bin");
setupInfo.ShadowCopyFiles = "true";
setupInfo.ConfigurationFile = configPath;
AppDomain appDomain = AppDomain.CreateDomain("Service for: " + setupInfo.ApplicationBase, AppDomain.CurrentDomain.Evidence, setupInfo);
object objHost = appDomain.CreateInstanceFromAndUnwrap(Path.Combine(setupInfo.PrivateBinPath, entryAssembly), entryType);
host = (IServiceHost)objHost;
return host;
}
Интерфейс IServiceHost
невероятно сложный: -
public interface IServiceHost
{
void Start();
void Stop();
}
Служба OnStart содержит что-то вроде этого: -
private List<IServiceHost> serviceHosts = new List<IServiceHost>();
protected override void OnStart(string[] args)
{
foreach (string configPaths in GetConfigPaths())
{
IServiceHost host = ServiceHostLoader.CreateServiceHost(configPath);
serviceHosts.Add(host);
host.Start();
}
}
OnStop
одинаково прямолинейный (теперь, чтобы все упростить, IServiceHost.Stop
блокирует вызовы).
protected override void OnStop()
{
foreach (IServiceHost host in serviceHosts)
{
host.Stop();
}
}
Это все достаточно просто и отлично работает при тестировании на машинах разработки. Однако в QA я получаю исключения, когда он остановлен. Когда в развитии мы закручиваем вещи только на короткий период, все кажется, что все работает нормально. Однако в QA услуга останавливается только каждые 24 часа. В этом случае он последовательно не может остановиться правильно.
Вот пример того, что заканчивается в журнале событий: -
Тип события: событие ошибки Источник: событие службы рабочего пространства Категория: нет КОД события: 0 Дата: 11/03/2011 Время: 08:00:00 Пользователь: нет данных Компьютер: QA-IIS-01 Описание: Не удалось остановить службу. System.Runtime.Remoting.RemotingException: объект '/50e76ee1_3f40_40a1_9311_1256a0375f7d/msjxeib0oy+s0sog1mkeikjd_2.rem' был отключен или не существуют на сервере.
Трассировка стека сервера: at System.Runtime.Remoting.Channels.ChannelServices.CheckDisconnectedOrCreateWellKnownObject(Шеззаде msg) при System.Runtime.Remoting.Channels.ChannelServices.SyncDispatchMessage(Шеззаде MSG)
Исключение, сброшенное в [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(Шеззаде reqMsg, IMessage retMsg) в System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData & msgData, тип Int32) при MyOrg.Service.IServiceHost.Stop() в MyOrg.Workspace.Service.MyAppService.OnStop() в System.ServiceProcess.ServiceBase.DeferredStop()
Дополнительные сведения см. в справке и Центр поддержки http://go.microsoft.com/fwlink/events.asp.
Теперь для тестовых целей фактический IServiceHost
просто записывает записи в журнал событий в виде сердечного ритма и записи, указывающие начало и остановку, и я только разворачиваю один AppDomain.
Казалось бы, со временем удаленный прокси-сервер для исполнителя IServiceHost
в домене приложения по умолчанию основного сервиса потерял связь с другим концом в сгенерированном домене.
Может ли кто-нибудь объяснить, почему это происходит, или предложить лучший способ для домена по умолчанию запрашивать сгенерированные домены в порядке очереди?
Ответы
Ответ 1
Удар в темноте. Срок действия лизинга на удаленном объекте истекает? Посмотрите MarshalByRefObject.InitializeLifetimeService. Чтобы сделать объект постоянным, просто переопределите и верните null
.
public override object InitializeLifetimeService()
{
// returning null here will prevent the lease manager
// from deleting the object.
return null;
}