Hay numerosas razones para crear servicios de ejecución larga, como:
Procesamiento de datos de uso intensivo de CPU.
Cola de elementos de trabajo en segundo plano
Realización de una operación basada en el tiempo según una programación
Normalmente, el procesamiento de servicios en segundo plano no implica una interfaz de usuario (UI), pero se pueden crear interfaces de usuario en torno a ellos. En los inicios de .NET Framework, los desarrolladores de Windows podían crear servicios de Windows para estos fines. Ahora, con .NET, puede usar BackgroundService, que es una implementación de IHostedService, o implementar el suyo propio.
Con .NET, ya no está limitado a Windows. Puede desarrollar servicios en segundo plano multiplataforma. Los servicios hospedados están listos para el registro, la configuración y la inserción de dependencias (ID). Forman parte del conjunto de extensiones de bibliotecas, lo que significa que son fundamentales para todas las cargas de trabajo de .NET que funcionan con el host genérico.
Importante
La instalación del SDK de .NET también instala Microsoft.NET.Sdk.Worker y la plantilla de trabajo. Es decir, después de instalar el SDK de .NET, puede crear un nuevo trabajo (“new worker”) mediante el comando dotnet new worker. Si usa Visual Studio, la plantilla se oculta hasta que se instala la carga de trabajo opcional de ASP.NET y desarrollo web.
Terminología
Muchos términos se usan erróneamente como sinónimos. En esta sección se definen algunos de estos términos para que su intención en este artículo sea más evidente.
Servicio de ejecución larga: cualquier servicio que se ejecuta continuamente.
Windows Service: la infraestructura de Windows Service, originalmente basada en .NET Framework, a la que se puede acceder ahora desde .NET.
Worker Service: la plantilla Servicio de trabajo.
Plantilla Worker Service
La plantilla Servicio de trabajo está disponible para la CLI de .NET y Visual Studio. Para más información, vea la plantilla dotnet new worker de la CLI de .NET. La plantilla consta de una clase Program y Worker.
Llama AddHostedService a para registrar Worker como un servicio hospedado.
Compila una interfaz IHost a partir del generador.
Llama a Run en la instancia de host, que ejecuta la aplicación.
Valores predeterminado de plantilla
La plantilla del rol de trabajo no habilita la recolección de elementos no utilizados del servidor (GC) de forma predeterminada, ya que hay numerosos factores que desempeñan un papel para determinar su necesidad. Todos los escenarios que requieren servicios de ejecución prolongada deben tener en cuenta las implicaciones de rendimiento de este valor predeterminado. Para habilitar la recolección de elementos no utilizados del servidor, agregue el nodo ServerGarbageCollection al archivo del proyecto:
Administración eficaz de memoria: reclama automáticamente memoria no utilizada para evitar pérdidas de memoria y optimizar el uso de recursos.
Rendimiento mejorado en tiempo real: evita posibles pausas o interrupciones causadas por la recolección de elementos no utilizados en aplicaciones sensibles a la latencia.
Estabilidad a largo plazo: ayuda a mantener un rendimiento estable en servicios de larga duración mediante la administración de memoria durante períodos prolongados.
Eficiencia de los recursos: puede conservar los recursos de CPU y memoria en entornos con restricción de recursos.
Mantenimiento reducido: minimiza la necesidad de administración manual de memoria, lo que simplifica el mantenimiento.
Control de memoria manual: proporciona un control específico sobre la memoria para aplicaciones especializadas.
Comportamiento predecible: contribuye al comportamiento de aplicación coherente y predecible.
Adecuado para procesos de corta duración: minimiza la sobrecarga de recolección de elementos no utilizados para procesos efímeros o de corta duración.
La clase Worker anterior es una subclase de BackgroundService, que implementa IHostedService. BackgroundService es abstract class y requiere la subclase para implementar BackgroundService.ExecuteAsync(CancellationToken). En la implementación de la plantilla, los bucles ExecuteAsync se recorren una vez por segundo, registrando la fecha y hora actuales hasta que se señale el proceso para la cancelación.
El archivo del proyecto
La plantilla Worker se basa en el siguiente archivo del proyecto Sdk:
Una aplicación basada en la plantilla Worker usa el SDK de Microsoft.NET.Sdk.Worker y tiene una referencia de paquete explícita al paquete Microsoft.Extensions.Hosting.
Contenedores y adaptabilidad a la nube
Con las cargas de trabajo de .NET más modernas, los contenedores son una opción viable. Al crear un servicio de ejecución larga a partir de la plantilla de Worker en Visual Studio, puede optar por la compatibilidad con Docker. Al hacerlo, se crea un Dockerfile que contiene la aplicación .NET. Un Dockerfile es un conjunto de instrucciones para compilar una imagen. En el caso de las aplicaciones .NET, el Dockerfile normalmente se encuentra en la raíz del directorio junto a un archivo de solución.
# See https://aka.ms/containerfastmode to understand how Visual Studio uses this
# Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/runtime:8.0@sha256:e6b552fd7a0302e4db30661b16537f7efcdc0b67790a47dbf67a5e798582d3a5 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:35792ea4ad1db051981f62b313f1be3b46b1f45cadbaa3c288cd0d3056eefb83 AS build
WORKDIR /src
COPY ["background-service/App.WorkerService.csproj", "background-service/"]
RUN dotnet restore "background-service/App.WorkerService.csproj"
COPY . .
WORKDIR "/src/background-service"
RUN dotnet build "App.WorkerService.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "App.WorkerService.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "App.WorkerService.dll"]
Los pasos anteriores del Dockerfile incluyen:
Establecer la imagen base de mcr.microsoft.com/dotnet/runtime:8.0 como el alias base.
Cambiar el directorio de trabajo a /app.
Establecer el alias build de la imagen mcr.microsoft.com/dotnet/sdk:8.0.
Cambiar el directorio de trabajo a /src.
Copiar el contenido y publicar la aplicación .NET:
La aplicación se publica mediante el comando dotnet publish.
Retransmitir la imagen del SDK de .NET desde mcr.microsoft.com/dotnet/runtime:8.0 (el alias base).
Copiar la salida de compilación publicada de /publish.
MRC en mcr.microsoft.com significa "Microsoft Container Registry", y es el catálogo de contenedores sindicados de Microsoft del centro de Docker oficial. El artículo Catálogo de contenedores sindicados de Microsoft contiene información adicional.
Al establecer Docker como destino de una estrategia de implementación para la plantilla de Worker Service de .NET, hay algunas consideraciones en el archivo del proyecto:
En el archivo del proyecto anterior, el elemento <DockerDefaultTargetOS> especifica Linux como destino. Para establecer los contenedores de Windows como destino, use Windows en su lugar. El paquete de NuGet Microsoft.VisualStudio.Azure.Containers.Tools.Targets se agrega automáticamente como una referencia de paquete cuando se selecciona la compatibilidad con Docker en la plantilla.
Si quiere utilizar los secretos de usuario con la plantilla Worker, tendría que hacer referencia explícitamente al paquete NuGet Microsoft.Extensions.Configuration.UserSecrets.
Estos dos métodos sirven como métodos de ciclo de vida: se invocan durante los eventos de inicio y de detección del host, respectivamente.
Nota
Al invalidar los métodos StartAsync o StopAsync, debe llamar y usar await con el método de clase base para garantizar que el servicio se inicia o se cierra adecuadamente.
Importante
La interfaz actúa como una restricción de parámetro de tipo genérico en el método de extensión AddHostedService<THostedService>(IServiceCollection), lo que significa que solo se permiten implementaciones. Puede usar la clase BackgroundService proporcionada con una subclase, o bien implementar la suya propia por completo.
Finalización de señal
En los escenarios más comunes, no es necesario indicar explícitamente la finalización de un servicio hospedado. Cuando el host inicia los servicios, están diseñados para ejecutarse hasta que se detenga el host. Sin embargo, en algunos escenarios, es posible que tenga que indicar la finalización de toda la aplicación host cuando se complete el servicio. Para señalar la finalización, considere el uso de la siguiente clase Worker:
namespace App.SignalCompletionService;
public sealed class Worker(
IHostApplicationLifetime hostApplicationLifetime,
ILogger<Worker> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// TODO: implement single execution logic here.
logger.LogInformation(
"Worker running at: {Time}", DateTimeOffset.Now);
await Task.Delay(1_000, stoppingToken);
// When completed, the entire app host will stop.
hostApplicationLifetime.StopApplication();
}
}
El origen de este contenido se puede encontrar en GitHub, donde también puede crear y revisar problemas y solicitudes de incorporación de cambios. Para más información, consulte nuestra guía para colaboradores.
Comentarios de .NET
.NET es un proyecto de código abierto. Seleccione un vínculo para proporcionar comentarios:
Comprenda e implemente la inserción de dependencias en una aplicación ASP.NET Core. Use el contenedor de servicios integrado de ASP.NET Core para administrar las dependencias. Registre los servicios con el contenedor de servicios.