tag route page net data asp all c# windows-services asp.net-core .net-core

c# - route - Hosting ASP.NET Core como servicio de Windows



forms asp net core (7)

A medida que lo consigo en RC2, hay un soporte para hospedar aplicaciones dentro de los Servicios de Windows. Intenté probarlo en un proyecto de api web simple (utilizando .NET Framework 4.6.1).

Aquí está mi código Program.cs:

using System; using System.IO; using System.Linq; using System.ServiceProcess; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.WindowsServices; namespace WebApplication4 { public class Program : ServiceBase { public static void Main(string[] args) { if (args.Contains("--windows-service")) { Run(new Program()); return; } var program = new Program(); program.OnStart(null); Console.ReadLine(); program.OnStop(); } protected override void OnStart(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup<Startup>() .Build(); host.RunAsService(); } protected override void OnStop() {} } }

Todas las demás cosas son básicamente de la plantilla .NET Core (aunque cambié framework a net461 y agregué algunas dependencias en project.json).

Después de publicarlo con dotnet publish y crear Windows Service con sc create puedo iniciar mi servicio con éxito, pero no puedo acceder a ninguno de mis controladores (los puertos no están listados). Asumo que estoy haciendo algo mal.

Así que supongo que la pregunta principal es cómo crear una API web alojada automáticamente y ejecutarla como Servicio de Windows. Todas las soluciones encontradas no funcionan después de la actualización RC2.


Actualizado para lo que uso para .netcore 2.1, utilizando la mayor cantidad posible de la plantilla de valores, que incluye la configuración de lectura de appsettings.json, comando args, filtrado de host, etc., implementado dentro de los métodos auxiliares del equipo de .netcore. Muchos de estos ajustes se controlan a través de archivos de configuración o argumentos de comando. verifique la documentación de microsoft sobre lo que proporciona la plantilla de inventario y sobre cómo anular la configuración.

Tenga en cuenta que he visto que el servicio no se inicia si define un punto final con https y el certificado de desarrollo predeterminado. Puede ser simplemente una cuestión de especificar un pfx a través de la configuración. Si alguien quiere mejorar esto, siéntase libre de hacerlo.

De todos modos, aquí está el código de plantilla de archivo que utilizo en program.cs

public class Program { public static void Main(string[] args) { if (args.Contains("--service")) { var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); Directory.SetCurrentDirectory(path); // need this because WebHost.CreateDefaultBuilder queries current directory to look for config files and content root folder. service start up sets this to win32''s folder. var host = CreateWebHostBuilder(args).Build(); host.RunAsService(); } else { CreateWebHostBuilder(args).Build().Run(); } } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>(); }


Aquí tiene un par de opciones: utilice la clase WebHostService de Microsoft, herede WebHostService o escriba el suyo. La razón de esto último es que utilizando la implementación de Microsoft, no podemos escribir un método de extensión genérico con un parámetro de tipo que herede WebHostService ya que esta clase no contiene un constructor sin parámetros ni podemos acceder al localizador de servicios.

Utilizando WebHostService

En este ejemplo, crearé una aplicación de consola que usa Microsoft.DotNet.Web.targets, genera un archivo .exe y funciona como una aplicación MVC (vistas, controladores, etc.). Supongo que crear la Aplicación de la Consola, cambiar los objetivos en .xproj y modificar el project.json para tener las opciones de publicación adecuadas y copiar las Vistas, los Controladores y webroot desde la plantilla estándar de la aplicación web .NET Core es trivial.

Ahora la parte esencial:

  1. Obtenga this paquete y asegúrese de que su marco en el archivo project.json sea net451 (o más reciente)

  2. Asegúrese de que la raíz del contenido en el punto de entrada esté correctamente establecida en el directorio de publicación del archivo .exe de la aplicación y que se llame al método de extensión RunAsService (). P.ej:

    public static void Main(string[] args) { var exePath= System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; var directoryPath = Path.GetDirectoryName(exePath); var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(directoryPath) .UseStartup<Startup>() .Build(); if (Debugger.IsAttached || args.Contains("--debug")) { host.Run(); } else { host.RunAsService(); } }

El .exe ahora se puede instalar fácilmente usando el siguiente comando

sc create MyService binPath = "Full/Path/To/The/Console/file.exe"

Una vez que se inicia el servicio, la aplicación web se aloja y encuentra con éxito sus Vistas.

Heredar WebHostService

Un beneficio importante de este enfoque es que nos permite anular los métodos OnStopping, OnStarting y OnStarted.

Supongamos que la siguiente es nuestra clase personalizada que hereda WebHostService

internal class CustomWebHostService : WebHostService { public CustomWebHostService(IWebHost host) : base(host) { } protected override void OnStarting(string[] args) { // Log base.OnStarting(args); } protected override void OnStarted() { // More log base.OnStarted(); } protected override void OnStopping() { // Even more log base.OnStopping(); } }

Siguiendo los pasos anteriores, tenemos que escribir nuestro propio método de extensión que ejecuta el host usando nuestra clase personalizada:

public static class CustomWebHostWindowsServiceExtensions { public static void RunAsCustomService(this IWebHost host) { var webHostService = new CustomWebHostService(host); ServiceBase.Run(webHostService); } }

La única línea que queda por cambiar del ejemplo anterior del punto de entrada es la instrucción else al final, tiene que llamar al método de extensión adecuado

host.RunAsCustomService();

Finalmente, instalando el servicio siguiendo los mismos pasos anteriores.

sc create MyService binPath = "Full/Path/To/The/Console/file.exe"


Debe hacer referencia a Microsoft.AspNetCore.Hosting y Microsoft.AspNetCore.Hosting.WindowsServices y usar este código en su clase de Inicio para que sea ejecutable como un servicio de Windows:

public static void Main(string[] args) { var host = new WebHostBuilder() .UseIISIntegration() .UseKestrel() .UseContentRoot(@"Path/To/Content/Root") .UseStartup<Startup>() .Build(); if (Debugger.IsAttached || args.Contains("--debug")) { host.Run(); } else { host.RunAsService(); } }

Luego, debe agregar un método de extensión para IWebHost.RunAsService para envolverlo con su clase personalizada WebHostService con los controladores de eventos OnStopping y OnStarting :

public static class MyWebHostServiceServiceExtensions { public static void RunAsMyService(this IWebHost host) { var webHostService = new MyWebHostService(host); ServiceBase.Run(webHostService); } } internal class MyWebHostService : WebHostService { public MyWebHostService(IWebHost host) : base(host) { } protected override void OnStarting(string[] args) { base.OnStarting(args); } protected override void OnStarted() { base.OnStarted(); } protected override void OnStopping() { base.OnStopping(); } }

Esta publicación Cómo alojar su Core ASP.NET en un servicio de Windows y los comentarios cubren los detalles.

ACTUALIZACIÓN (ver más detalles en Resumen rápido de las novedades de ASP.NET Core 2.0 ):

En ASP.NET Core 1.1 tuvimos algo como esto:

public class Program { public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .Build(); host.Run(); } }

En ASP.NET Core 2.0 , se ve así:

public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .Build(); }


Encontré este tema mientras buscaba una solución a un problema similar. Terminé implementando algo que funciona bastante parecido a Topshelf muy (muy) simplificado. Puede ejecutarse fácilmente como consola y / o instalar, desinstalar y así uno como servicio. Creo que puede ser bastante útil para alguien. Puede encontrar el código aquí: https://github.com/PeterKottas/DotNetCore.WindowsService y también hay nuget aquí https://www.nuget.org/packages/PeterKottas.DotNetCore.WindowsService/ . Disfrutar :)


Los servicios de Windows se pueden crear fácilmente con Visual Studio 2017. Necesitará mover su código .NET Core a una biblioteca de clases que apunta a NetStandard, a la que luego se puede hacer referencia. El proyecto de su servicio de Windows tendrá que apuntar al completo .NET Framework pero puede hacer referencia a su biblioteca compartida.

Al colocar todo su código en la biblioteca de clases, tendrá la portabilidad entre el Servicio de Windows y otras aplicaciones que no sean de Windows.

Con VS 2015 no pudo realizar un proyecto de servicio de Windows y hacer referencia a .NET Core xproj. Visual Studio 2017 corrige que una vez que conviertes todos tus proyectos a csproj.

Este blog lo explica con más detalle: Cómo crear .NET Core Windows Services con Visual Studio 2017


Si está bien ejecutar solo en .NET Framework completo, las respuestas anteriores son suficientes (heredar de ServiceBase o usar WebHostService de Microsoft).

Sin embargo, si tiene / desea ejecutar solo .NET Core (por ejemplo, en el servidor Windows Nano, un binario único que funciona en Linux como una aplicación normal y como un servicio en Windows, o necesita ejecutar una al lado de la otra en un La versión anterior de .NET Framework (por lo que no puede actualizar el marco del sistema), tendría que realizar las llamadas a la API de Windows adecuadas a través de P / Invokes. Como tenía que hacer eso, creé una biblioteca que hace exactamente eso .

Hay una sample disponible que también se puede instalar cuando se ejecuta con privilegios administrativos (por ejemplo, dotnet MyService.dll --register-as-service ).


Utilizando la última plantilla de la aplicación web principal VS.NET ASP202 (.NET Framework) y con los mods a Program.cs como se muestra a continuación, funciona bien cuando se ejecuta como un servicio, independiente y en VS. Observe que la ruta al directorio que contiene wwwroot debe configurarse cuando se ejecuta como un servicio.

Hasta ahora, me gusta mucho esta plantilla y patrón. Puede desarrollar código MVC6 como es habitual en Visual Studio y luego se implementa de forma limpia como un servicio. De hecho, noté que al implementar una instancia local del servicio para probar que no hay necesidad de eliminar / crear el servicio usando sc.exe. Simplemente detenga el servicio, publique el código y reinicie el servicio, que recogerá los nuevos cambios.

public class Program { public static void Main(string[] args) { IWebHost host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .Build(); if (args.Contains("--windows-service")) { host = new WebHostBuilder() .UseKestrel() .UseContentRoot("<directory-containing-wwwroot>") .UseIISIntegration() .UseStartup<Startup>() .UseUrls("http://+:5000") .Build(); Startup.is_service = true; host.RunAsService(); } else { host.Run(); } } }