Запуск службы Topshelf с использованием ConfigureServiceInIsolation - универсальный хост
Я разрабатываю очень простое решение Generic Host, которое позволит нам размещать сборки в качестве служб Windows (аля NServiceBus). Я сталкиваюсь со следующим исключением (похожим на комментарии, упомянутые в посте Дру). Мне нужно, чтобы это работало, чтобы я мог размещать сервисы в разных доменах приложений.
"Введите 'MyProject.WindowsServices.GenericHost.Program+<>c__DisplayClass5' в сборке" MyProject.WindowsServices.GenericHost, Version=1.0.0.0, Culture= нейтральный, PublicKeyToken=null'не помечен как сериализуемый."
Я использую бинарные файлы Topshelf 1.0 RC, доступные по ссылке для скачивания на домашней странице topshelf (topshelf-project.com). Я попробовал последнюю сборку (29/07/2010), и сборки доступны для загрузки с Google Code и GitHub! Я не могу заставить никого из них работать на меня!
Это работает в библиотеке NServiceBus с более старой версией Topshelf (dll имеет версию 0.8.0.96). С некоторыми незначительными изменениями кода в том, что у меня есть ниже (используйте CreateServiceLocator вместо HowToBuildService), он работает для меня с этими более старыми двоичными файлами, но я бы предпочел придерживаться новейшего кода, чтобы воспользоваться преимуществами любых запланированных исправлений или улучшений.
Вот мой код
static void Main(string[] args)
{
ArgumentParser arguments = new ArgumentParser(args);
string configFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
arguments.ServiceType.Assembly.ManifestModule.Name + ".config");
RunConfiguration cfg = RunnerConfigurator.New(x =>
{
x.SetServiceName(arguments.ServiceName);
x.SetDisplayName(arguments.DisplayName);
x.SetDescription(arguments.Description);
if (string.IsNullOrEmpty(arguments.UserName))
{
x.RunAsLocalSystem();
}
else
{
x.RunAs(arguments.UserName, arguments.Password);
}
x.ConfigureServiceInIsolation<GenericHost>(c =>
{
c.ConfigurationFile(configFile);
c.Named(arguments.ServiceType.AssemblyQualifiedName);
c.HowToBuildService(name => new GenericHost(arguments.ServiceType));
c.WhenStarted(tc => tc.Start());
c.WhenStopped(tc => tc.Stop());
});
});
Runner.Host(cfg, args);
}
Также следует отметить, что мой класс GenericHost и класс, идентифицируемый по аргументам. Оба сервиса реализуют MarshalByRefObject, и я также сделал эти классы Serializable, чтобы посмотреть, поможет ли это. Проблема возникает не в этих классах, а в том, что он жалуется на анонимный тип, сгенерированный компилятором C# для одной или нескольких лямбда-зондов, которые я настроил.
Кто-нибудь еще видел эту проблему с использованием ConfigureServiceInIsolation()? Если нет, кто-нибудь знает, что мне здесь не хватает? Дайте мне знать, если вам нужна дополнительная информация, например, трассировка стека или больше кода.
1 ответ
Если вы используете только один сервис внутри хоста, я бы удалил "InIsolation". Это не работает правильно, но в будущей версии TopShelf (мы сейчас над этим работаем), я думаю, у нас есть лучший ответ на этот вопрос. Помимо возможности просто перетаскивать файлы на хосте и делать так, чтобы ваш сервис автоматически раскручивался в новом домене приложений.
Я бы сказал, что это относится к известной проблеме, и, если нет веских причин для использования InIsolation, избегайте ее на данный момент. Вы не можете распределить лямбда-выражения через барьеры домена приложения, поэтому проблема, с которой вы столкнулись. Если проблема InIsolation достаточно важна, я могу попытаться исправить ее в зависимости от сроков, прежде чем мы планируем выпустить последнюю версию. [Вы можете взять последнюю версию Dev. немного отсюда: http://github.com/legomaster/Topshelf - предупреждение, мы все еще находимся в активной разработке, но я думаю, что все основные ошибки теперь устранены].
Если вы хотите обсудить это дальше, возможно, будет проще всего опубликовать в списке MassTransit, где следят все разработчики: http://groups.google.com/group/masstransit-discuss
Надеюсь, это поможет!