Установка службы Windows без InstallUtil.exe
Я пытаюсь развернуть службу Windows, но не совсем уверен, как это сделать правильно. Для начала я создал его как консольное приложение, теперь я превратил его в проект службы Windows и просто вызываю мой класс из метода OnStart в службе.
Теперь мне нужно установить его на сервер, на котором нет Visual Studio, что, если я правильно понял, означает, что я не могу использовать InstallUtil.exe и должен вместо этого создать класс установщика. Это правильно?
Я уже взглянул на предыдущий вопрос: установить службу Windows.NET без InstallUtil.exe, но я просто хочу убедиться, что правильно понял.
Если я создам класс, на который есть ответ на вопрос, на который ответят вопросы, каков будет следующий шаг? Загрузите MyService.exe и MyService.exe.config на сервер, дважды щелкните исполняемый файл, и Боб мой дядя?
Служба будет установлена только на одном сервере.
8 ответов
InstallUtil.exe
Инструмент - это просто оболочка для некоторых вызовов отражений против компонента (ов) установщика в вашем сервисе. Как таковой, он на самом деле ничего не делает, но использует функциональность, которую обеспечивают эти компоненты установщика. Решение Марка Гравелла просто предоставляет способ сделать это из командной строки, чтобы вам больше не приходилось полагаться на InstallUtil.exe
на целевой машине.
Вот мой шаг за шагом, основанный на решении Марка Гравелла.
Как сделать так, чтобы.NET Windows Service запускался сразу после установки?
Я знаю, что это очень старый вопрос, но лучше обновите его новой информацией.
Вы можете установить сервис, используя команду sc:
InstallService.bat:
@echo OFF
echo Stopping old service version...
net stop "[YOUR SERVICE NAME]"
echo Uninstalling old service version...
sc delete "[YOUR SERVICE NAME]"
echo Installing service...
rem DO NOT remove the space after "binpath="!
sc create "[YOUR SERVICE NAME]" binpath= "[PATH_TO_YOUR_SERVICE_EXE]" start= auto
echo Starting server complete
pause
С помощью SC вы также можете сделать гораздо больше: удалить старую службу (если вы уже установили ее ранее), проверить, существует ли служба с таким же именем... даже установить автоматический запуск вашей службы.
Одна из многочисленных ссылок: создание сервиса с помощью sc.exe; как передать в контекст параметры
Я сделал так и InstallUtil
, Лично я чувствую, что использование SC чище и полезнее для вашего здоровья.
Вы все еще можете использовать installutil без visual studio, он включен в.net framework
На вашем сервере откройте командную строку от имени администратора, а затем:
CD C:\Windows\Microsoft.NET\Framework\v4.0.version (insert your version)
installutil "C:\Program Files\YourWindowsService\YourWindowsService.exe" (insert your service name/location)
Чтобы удалить:
installutil /u "C:\Program Files\YourWindowsService\YourWindowsService.exe" (insert your service name/location)
Это базовый класс обслуживания (подкласс ServiceBase), который можно разделить на подклассы для создания службы Windows, которую можно легко установить из командной строки, без installutil.exe. Это решение является производным от Как запустить.NET Windows Service сразу после установки?, добавив некоторый код, чтобы получить тип сервиса, используя вызывающий StackFrame
public abstract class InstallableServiceBase:ServiceBase
{
/// <summary>
/// returns Type of the calling service (subclass of InstallableServiceBase)
/// </summary>
/// <returns></returns>
protected static Type getMyType()
{
Type t = typeof(InstallableServiceBase);
MethodBase ret = MethodBase.GetCurrentMethod();
Type retType = null;
try
{
StackFrame[] frames = new StackTrace().GetFrames();
foreach (StackFrame x in frames)
{
ret = x.GetMethod();
Type t1 = ret.DeclaringType;
if (t1 != null && !t1.Equals(t) && !t1.IsSubclassOf(t))
{
break;
}
retType = t1;
}
}
catch
{
}
return retType;
}
/// <summary>
/// returns AssemblyInstaller for the calling service (subclass of InstallableServiceBase)
/// </summary>
/// <returns></returns>
protected static AssemblyInstaller GetInstaller()
{
Type t = getMyType();
AssemblyInstaller installer = new AssemblyInstaller(
t.Assembly, null);
installer.UseNewContext = true;
return installer;
}
private bool IsInstalled()
{
using (ServiceController controller =
new ServiceController(this.ServiceName))
{
try
{
ServiceControllerStatus status = controller.Status;
}
catch
{
return false;
}
return true;
}
}
private bool IsRunning()
{
using (ServiceController controller =
new ServiceController(this.ServiceName))
{
if (!this.IsInstalled()) return false;
return (controller.Status == ServiceControllerStatus.Running);
}
}
/// <summary>
/// protected method to be called by a public method within the real service
/// ie: in the real service
/// new internal void InstallService()
/// {
/// base.InstallService();
/// }
/// </summary>
protected void InstallService()
{
if (this.IsInstalled()) return;
try
{
using (AssemblyInstaller installer = GetInstaller())
{
IDictionary state = new Hashtable();
try
{
installer.Install(state);
installer.Commit(state);
}
catch
{
try
{
installer.Rollback(state);
}
catch { }
throw;
}
}
}
catch
{
throw;
}
}
/// <summary>
/// protected method to be called by a public method within the real service
/// ie: in the real service
/// new internal void UninstallService()
/// {
/// base.UninstallService();
/// }
/// </summary>
protected void UninstallService()
{
if (!this.IsInstalled()) return;
if (this.IsRunning()) {
this.StopService();
}
try
{
using (AssemblyInstaller installer = GetInstaller())
{
IDictionary state = new Hashtable();
try
{
installer.Uninstall(state);
}
catch
{
throw;
}
}
}
catch
{
throw;
}
}
private void StartService()
{
if (!this.IsInstalled()) return;
using (ServiceController controller =
new ServiceController(this.ServiceName))
{
try
{
if (controller.Status != ServiceControllerStatus.Running)
{
controller.Start();
controller.WaitForStatus(ServiceControllerStatus.Running,
TimeSpan.FromSeconds(10));
}
}
catch
{
throw;
}
}
}
private void StopService()
{
if (!this.IsInstalled()) return;
using (ServiceController controller =
new ServiceController(this.ServiceName))
{
try
{
if (controller.Status != ServiceControllerStatus.Stopped)
{
controller.Stop();
controller.WaitForStatus(ServiceControllerStatus.Stopped,
TimeSpan.FromSeconds(10));
}
}
catch
{
throw;
}
}
}
}
Все, что вам нужно сделать, это реализовать два публичных / внутренних метода в вашем реальном сервисе:
new internal void InstallService()
{
base.InstallService();
}
new internal void UninstallService()
{
base.UninstallService();
}
а затем позвоните им, когда вы хотите установить службу:
static void Main(string[] args)
{
if (Environment.UserInteractive)
{
MyService s1 = new MyService();
if (args.Length == 1)
{
switch (args[0])
{
case "-install":
s1.InstallService();
break;
case "-uninstall":
s1.UninstallService();
break;
default:
throw new NotImplementedException();
}
}
}
else {
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(MyService);
}
}
Почему бы просто не создать проект установки? Это действительно легко.
- Добавьте установщик службы в службу (вы делаете это на кажущейся бесполезной "дизайнерской" поверхности службы)
- Создайте проект установки и добавьте выход службы в папку приложения установки
- Наиболее важно добавить выходные данные проекта службы ко всем настраиваемым действиям.
Вуаля, и все готово.
Смотрите здесь для получения дополнительной информации: http://www.codeproject.com/KB/dotnet/simplewindowsservice.aspx
Существует также способ запросить у пользователя учетные данные (или указать свои собственные).
Topshelf - это проект OSS, который был запущен после того, как на этот вопрос был дан ответ, и он значительно облегчает обслуживание Windows. Я очень рекомендую изучить его.
Эта проблема связана с безопасностью, лучше откройте командную строку разработчика для VS 2012 в RUN AS ADMINISTRATOR и установите вашу службу, это наверняка решит вашу проблему.
Не двойной щелчок, вы запускаете его с правильными параметрами командной строки, поэтому введите что-то вроде MyService -i
а потом MyService -u
удалить его`.
В противном случае вы можете использовать sc.exe для установки и удаления (или скопировать вместе с InstallUtil.exe).