c# - tutorial - Instale el servicio de Windows sin InstallUtil.exe
windows service installer (8)
Estoy intentando implementar un servicio de Windows pero no estoy seguro de cómo hacerlo bien. Para empezar, lo construí como una aplicación de consola, ahora lo he convertido en un proyecto de servicio de Windows y simplemente llamo a mi clase desde el método OnStart en el servicio.
Ahora necesito instalar esto en un servidor que no tiene Visual Studio, que si lo entendí correctamente significa que no puedo usar InstallUtil.exe y tengo que crear una clase de instalador. ¿Es esto correcto?
Eché un vistazo a una pregunta anterior, Instalar un servicio de Windows .NET sin InstallUtil.exe , pero solo quiero asegurarme de haberlo entendido correctamente.
Si creo la clase a la que responde la respuesta aceptada de la pregunta, ¿cuál es el siguiente paso? Cargue MyService.exe y MyService.exe.config en el servidor, haga doble clic en el archivo exe y Bob en mi tío?
El servicio solo se instalará en un servidor.
¿Por qué no simplemente crear un proyecto de instalación? Es realmente fácil.
- Agregue un instalador de servicio al servicio (lo hace en la superficie de "diseño" de servicio aparentemente inútil)
- Cree un proyecto de instalación y agregue el resultado del servicio a la carpeta de la aplicación de configuración
- Lo más importante es agregar el resultado del proyecto de servicio a todas las acciones personalizadas
Voila, y listo.
Consulte aquí para obtener más información: http://www.codeproject.com/KB/dotnet/simplewindowsservice.aspx
También hay una forma de solicitar al usuario las credenciales (o proporcionar las suyas).
No haga doble clic, lo ejecuta con los parámetros de línea de comando correctos, así que escriba algo como MyService -i
y luego MyService -u
para desinstalarlo.
De lo contrario, podría usar sc.exe para instalarlo y desinstalarlo (o copiarlo junto con InstallUtil.exe).
Aún puede usar installutil sin Visual Studio, se incluye con .NET Framework
En su servidor, abra un símbolo del sistema como administrador y luego:
CD C:/Windows/Microsoft.NET/Framework/v4.0.version (insert your version)
installutil "C:/Program Files/YourWindowsService/YourWindowsService.exe" (insert your service name/location)
Para desinstalar:
installutil /u "C:/Program Files/YourWindowsService/YourWindowsService.exe" (insert your service name/location)
Topshelf es un proyecto OSS que se inició después de que esta pregunta fue respondida y hace que el servicio de Windows sea mucho, MUCHO más fácil. Recomiendo encarecidamente investigarlo.
Este problema se debe a la seguridad, mejor abra el indicador de comandos del desarrollador para VS 2012 en EJECUTAR COMO ADMINISTRADOR e instale su servicio. Solucione su problema seguramente.
Esta es una clase de servicio base (subclase de ServiceBase) que se puede subclasificar para construir un servicio de Windows que se puede instalar fácilmente desde la línea de comandos, sin installutil.exe. Esta solución se deriva de ¿Cómo hacer que un servicio Windows .NET comience justo después de la instalación? , agregando un código para obtener el tipo de servicio utilizando el StackFrame que realiza la llamada
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;
}
}
}
}
Todo lo que tiene que hacer es implementar dos métodos públicos / internos en su servicio real:
new internal void InstallService()
{
base.InstallService();
}
new internal void UninstallService()
{
base.UninstallService();
}
y luego llamarlos cuando desee instalar el servicio:
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);
}
}
Sé que es una pregunta muy antigua, pero mejor actualizarla con nueva información.
Puede instalar el servicio usando el comando 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
Con SC, también puedes hacer muchas más cosas: desinstalar el servicio anterior (si ya lo has instalado anteriormente), verificar si existe el servicio con el mismo nombre ... incluso configurar tu servicio para el inicio automático.
Una de las muchas referencias: crear un servicio con sc.exe; cómo pasar parámetros de contexto
Lo he hecho de esta manera e InstallUtil
. Personalmente siento que usar SC es más limpio y mejor para tu salud.
La herramienta InstallUtil.exe
es simplemente un contenedor de algunas llamadas de reflexión contra los componentes del instalador en su servicio. Como tal, realmente no hace mucho más que ejercitar la funcionalidad que proporcionan estos componentes del instalador. La solución de Marc Gravell simplemente proporciona un medio para hacer esto desde la línea de comandos para que ya no tenga que depender de tener InstallUtil.exe
en la máquina de destino.
Aquí está mi paso a paso basado en la solución de Marc Gravell.
¿Cómo hacer que un servicio Windows .NET comience justo después de la instalación?