2010-05-18 65 views
31

Estoy tratando de 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.Instalar el servicio de Windows sin InstallUtil.exe

Ahora necesito instalar esto en un servidor que no tiene Visual Studio, que si lo he entendido correctamente significa que no puedo usar InstallUtil.exe y tengo que crear una clase de instalador en su lugar. ¿Es esto correcto?

He echado un vistazo a una pregunta anterior, Install a .NET windows service without InstallUtil.exe, pero solo quiero asegurarme de haberlo entendido correctamente.

Si creo la clase a la que responde la respuesta aceptada, ¿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.

+0

duplicado - http://stackoverflow.com/questions/255056/install-a-net-windows-service-without-installutil-exe –

+0

@AZ Sí, lo sé, pensé que estaría bien hacer la pregunta de todos modos, ya que me estoy refiriendo a la pregunta anterior y la mía es ligeramente diferente en que no es un servicio .NET (no tiene ninguna interfaz), por lo quería asegurarse de que se aplicaran las mismas respuestas. – annelie

Respuesta

17

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.

How to make a .NET Windows Service start right after the installation?

+0

Gracias, estoy casi allí con esto. Recibo una excepción de seguridad que dice 'No se encontró la fuente, pero algunos o todos los registros de eventos no se pudieron buscar. Registros inaccesibles: Seguridad '.Supongo que esto podría tener que ver con la cuenta en la que se está ejecutando, como @ho está hablando en su comentario. Lo configuré para LocalService, pero lo cambiaré e intentaré de nuevo. Por cierto, pequeño error ortográfico en su código, para InstallService() dice 'IDictionary state = new Hasttable();' en lugar de Hashtable. – annelie

+0

Solucionado. Gracias. –

+0

Sin problemas. Correcto, lo he intentado con todas las cuentas diferentes, todas menos el Usuario da la misma excepción, y para el Usuario debo ingresar el nombre de usuario y la contraseña. ¿Qué nombre de usuario y contraseña deberían ser? ¿Para el usuario que estoy iniciando sesión en el servidor? – annelie

0

No haga doble clic, lo ejecuta con los parámetros de línea de comando correctos, escriba algo así como MyService -i y luego MyService -u para desinstalarlo`.

De lo contrario, podría usar sc.exe para instalar y desinstalar (o copiar junto con InstallUtil.exe).

5

¿Por qué no crear un proyecto de configuración? Es realmente fácil.

  1. Añadir un instalador de servicio al servicio (lo haces en el servicio aparentemente inútil "diseño" de la superficie)
  2. Crear un proyecto de instalación y añadir la salida de servicio a la carpeta de aplicación de configuración
  3. Lo más importante es añadir el resultado del proyecto de servicio para todas las acciones personalizadas

Voila, y listo.

Consulte aquí para obtener más: http://www.codeproject.com/KB/dotnet/simplewindowsservice.aspx

También hay una manera de indicar al usuario las credenciales (o proporcionar su propia).

+0

Gracias, echaré un vistazo a esto si no consigo que las otras sugerencias funcionen. ¿No estás seguro de qué credenciales quieres decir? – annelie

+0

Con credenciales, se refiere a la cuenta bajo la cual se ejecuta el servicio. –

+0

@ho ¿En qué cuenta debe ejecutarse el servicio? Básicamente, el servicio mira algunas carpetas para nuevos archivos, carga archivos a una base de datos si hay nuevos archivos y luego mueve los archivos a una carpeta diferente. – annelie

28

Puede seguir utilizando installutil sin Visual Studio, que se incluye con el.NET Framework

En el servidor, abra un símbolo del sistema como administrador a continuación:

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) 
30

Sé que es una pregunta muy antigua, pero mejor actualizarlo con nueva información.

Puede instalar el servicio mediante el uso de sc comando:

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, se puede hacer mucho más cosas así: desinstalar el antiguo servicio (si ya lo instalé antes), verificando si existe servicio con el mismo nombre ... incluso configura tu servicio para el arranque automático.

Una de las muchas referencias: creating a service with sc.exe; how to pass in context parameters

he hecho tanto por esta manera & InstallUtil. Personalmente siento que usar SC es más limpio y mejor para tu salud.

+2

Esto es súper fácil y debería ser votado mucho más que los otros métodos. – Sam

+3

Creo que esta es la manera más fácil de instalar un servicio de Windows – ykh

+1

Estoy de acuerdo, esta es la solución más fácil y debería ser mucho más que las otras soluciones UBER COMPLEX. ¡Buen material! –

0

Topshelf es un proyecto OSS que se inició después de que se respondió esta pregunta y hace que el servicio de Windows sea mucho, MUCHO más fácil. Lo recomiendo encarecidamente.

http://topshelf-project.com/

0

Este problema es debido a la seguridad, solicitud de comando desarrollador Mejor abierta para VS 2012 en Ejecutar como administrador e instalar el servicio, se soluciona el problema de seguridad.

2

Esta es una clase de servicio base (subclase ServiceBase) que se puede subclasificar para crear 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 How to make a .NET Windows Service start right after the installation?, añadiendo un poco de código para obtener el tipo de servicio utilizando el StackFrame llamando

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/interno del sector público en su verdadero servicio:

new internal void InstallService() 
    { 
     base.InstallService(); 
    } 
    new internal void UninstallService() 
    { 
     base.UninstallService(); 
    } 

y luego llamarlos cuando se desea 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);    
     } 

    } 
Cuestiones relacionadas