#c# #windows-services #installation
#c# #windows-services #установка
Вопрос:
Я создаю проект службы Windows в VS2010, который содержит несколько служб. Я попытался найти способ установить его без сложного установщика. Но, похоже, он откатывается и не работает.
Вот Program.cs:
static class Program
{
static void Main(string[] args)
{
bool install = false, uninstall = false, console = false;
WindowsServiceInstaller inst = new WindowsServiceInstaller();
if (args.Length > 0)
{
foreach (string arg in args)
{
switch (arg)
{
case "-i":
case "-install":
install = true;
break;
case "-u":
case "-uninstall":
uninstall = true;
break;
case "-c":
case "-console":
console = true;
break;
default:
Console.Error.WriteLine("Argument not expected: " arg);
break;
}
}
}
if (uninstall)
{
inst.InstallServices(false, args);
}
if (install)
{
inst.InstallServices(true, args);
}
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
// scans Email table for outbound email jobs; uses multiple threads to lock and work on data in Email table
new EmailLogScanner()
// generates email digest of document status on secheduled basis; single thread
, new EmailStatusDigester()
// keeps Fax table and third-party fax service accounts synchronized; uses a fixed nb of threads, one thread syncs one account at a time
, new FaxSynchronizer()
};
if (console)
{
foreach (IDebuggableService srv in ServicesToRun)
{
string[] strs = new string[] { String.Empty };
srv.DebugStart(strs);
}
Console.WriteLine("Press any key to terminate...");
Console.ReadKey();
foreach (IDebuggableService srv in ServicesToRun)
{
srv.DebugStop();
}
Console.WriteLine("Service has exited.");
}
else
{
ServiceBase.Run(ServicesToRun);
}
}
}
Вот WindowsServiceInstaller.cs:
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
{
public WindowsServiceInstaller()
{
ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller();
serviceProcessInstaller.Account = ServiceAccount.NetworkService;
serviceProcessInstaller.Username = null;
serviceProcessInstaller.Password = null;
Installers.Add(serviceProcessInstaller);
ServiceInstaller emailLogScannerInstaller = new ServiceInstaller();
emailLogScannerInstaller.DisplayName = "Email Scanner";
emailLogScannerInstaller.StartType = ServiceStartMode.Automatic;
emailLogScannerInstaller.ServiceName = "EmailLogScanner"; // must match the ServiceBase ServiceName property
emailLogScannerInstaller.Description = "Scan for and sends out pending emails in stack.";
Installers.Add(emailLogScannerInstaller);
ServiceInstaller emailStatusDigesterInstaller = new ServiceInstaller();
emailStatusDigesterInstaller.DisplayName = "Status Digester";
emailStatusDigesterInstaller.StartType = ServiceStartMode.Automatic;
emailStatusDigesterInstaller.ServiceName = "EmailDigester";
emailStatusDigesterInstaller.Description = "Prepares document status email digests.";
Installers.Add(emailStatusDigesterInstaller);
ServiceInstaller faxSynchronizerInstaller = new ServiceInstaller();
faxSynchronizerInstaller.DisplayName = "Fax Synchronizer";
faxSynchronizerInstaller.StartType = ServiceStartMode.Automatic;
faxSynchronizerInstaller.ServiceName = "FaxSynchronizer";
faxSynchronizerInstaller.Description = "Synchronizes database with external fax service(s).";
Installers.Add(faxSynchronizerInstaller);
}
public void InstallServices(bool doInstall, string[] args)
{
try
{
using (AssemblyInstaller aInstaller = new AssemblyInstaller(typeof(Program).Assembly, args))
{
IDictionary state = new Hashtable();
aInstaller.UseNewContext = true;
try
{
if (doInstall)
{
aInstaller.Install(state);
aInstaller.Commit(state);
}
else
{
aInstaller.Uninstall(state);
}
}
catch
{
try
{
aInstaller.Rollback(state);
}
catch { }
throw;
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
}
}
Зарегистрированные выходные данные (когда я запускаю daemon.exe -i
в командном окне от имени администратора) показывают текст ниже. Кроме того, я получаю диалоговое окно «не удается запустить службу из командной строки»:
Installing assembly 'C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.exe'.
Affected parameters are:
i =
assemblypath = C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.exe
logfile = C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.InstallLog
Installing service EmailLogScanner...
Service EmailLogScanner has been successfully installed.
Creating EventLog source EmailLogScanner in log Application...
See the contents of the log file for the C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.exe assembly's progress.
The file is located at C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.InstallLog.
Rolling back assembly 'C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.exe'.
Affected parameters are:
logtoconsole =
i =
assemblypath = C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.exe
logfile = C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.InstallLog
Restoring event log to previous state for source EmailLogScanner.
Service EmailLogScanner is being removed from the system...
Service EmailLogScanner was successfully removed from the system.
ОБНОВЛЕНИЕ: Когда я комментирую блок try … catch вокруг ‘aInstaller.Строка Install (state)’, я получаю немного другой вывод:
Installing assembly 'C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.exe'.
Affected parameters are:
i =
assemblypath = C:UsersxxxDocuments~BusinessProjectsDa
emonbinReleaseDaemon.exe
logfile = C:UsersxxxDocuments~BusinessProjectsDaemon
binReleaseDaemon.InstallLog
Installing service EmailLogScanner...
Creating EventLog source EmailLogScanner in log Application...
Source EmailLogScanner already exists on the local computer.
Это потому, что у меня уже настроены источники журнала событий? Если да, то как мне пропустить этот шаг в AssemblyInstaller? Если нет, то что? 🙂
Комментарии:
1. И что
The file is located at C:UsersxxxDocuments~BusinessProjectsDaemonbinReleaseDaemon.InstallLog
сказал?2. На самом деле, последний блок выше — это то, что записано в файл InstallLog.
3. о, тогда разве проблема не в этом? «Исходный EmailLogScanner уже существует на локальном компьютере».? Похоже, что, возможно, вы создаете источник события каждый раз при установке, но, предположительно, удаление не означает удаление источника события. Поэтому в последующие разы не удается создать его, поскольку он уже существует.
4. Спасибо, вы заставили меня заметить, что было не так.
Ответ №1:
Вы должны поместить это
if (EventLog.SourceExists("YourEventSourceName"))
EventLog.DeleteEventSource("YourEventSourceName");
когда начнется установка службы.
Комментарии:
1. На самом деле, моя проблема была вариантом этого. В сборке у меня есть три разных службы. В каждой службе у меня есть код, который создал EventSource в конструкторе ServiceBase. Похоже, что ServiceInstaller не проверяет, прежде чем попытается создать EventSource, и, следовательно, конфликт. Я перенес код-нарушитель в другой метод, чтобы я мог создать исходный код, если служба была запущена через консоль.