Background tasks with hosted services in ASP.NET Core

How to Use HostedService in .NET Core for Background Processing

In many web applications or APIs, there are tasks that need to be performed periodically or in the background without interrupting the main application flow. For such scenarios, .NET Core provides a feature called HostedService. A HostedService runs as a background task managed by the application’s lifetime and can perform various tasks, such as processing data, sending notifications, or performing other background operations.

In this blog post, we will explore how to use HostedService in .NET Core to implement a video processing service. We’ll simulate video processing by generating thumbnails for unprocessed videos at regular intervals.

Prerequisites: To follow along, you should have a basic understanding of .NET Core and Visual Studio or any other .NET Core IDE.

Step 1: Set up the Project Create a new .NET Core web application project in Visual Studio or your preferred IDE. Choose the “ASP.NET Core Web Application” template and select “API” as the project type.

Step 2: Define the Video Model We’ll start by defining the Video model to represent a video entity. Add the following Video class to your project:

namespace HostedService.Models
{
    public class Video
    {
        public int Id { get; set; }
        public string? Title { get; set; }
        public string? File { get; set; }
        public bool IsProcessed { get; set; } = false;

    }

}

Step 3: Implement the VideoService Next, let’s create a service that will manage the video processing. The IVideoService interface defines the contract for managing videos, and the VideoService class implements this interface.

using HostedService.Models;

namespace HostedService.Service
{
    public interface IVideoService
    {
        List<Video> GetUnprocessedVideos();
        void AddVideo(Video video);
        void MarkAsProcessed(int videoId);
    }

    public class VideoService : IVideoService
    {
        private List<Video> _videos;
        private int _nextVideoId = 1;

        public VideoService()
        {
            _videos = new List<Video>();
        }

        public List<Video> GetUnprocessedVideos()
        {
            return _videos.Where(v => !v.IsProcessed).ToList();
        }

        public void AddVideo(Video video)
        {
            _videos.Add(video);
        }

        public void MarkAsProcessed(int videoId)
        {
            var video = _videos.FirstOrDefault(v => v.Id == videoId);
            if (video != null)
            {
                video.IsProcessed = true;
            }
        }

        public int GetNextVideoId()
        {
            return _nextVideoId++;
        }
    }

}

Step 4: Create the VideoProcessingService HostedService Now, let’s implement the VideoProcessingService as a HostedService. This service will run in the background and simulate video processing by generating thumbnails for unprocessed videos.

namespace HostedService.Service
{
    public class VideoProcessingService : IHostedService, IDisposable
    {
        private readonly ILogger<VideoProcessingService> _logger;
        private readonly IVideoService _videoService;
        private Timer _timer;

        public VideoProcessingService(ILogger<VideoProcessingService> logger, IVideoService videoService)
        {
            _logger = logger;
            _videoService = videoService;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("VideoProcessingService is starting.");

            // Create a Timer that will run the ExecuteAsync method on a specified interval.
            _timer = new Timer(ExecuteAsync,
                               null,
                               TimeSpan.Zero,
                               TimeSpan.FromSeconds(5));

            return Task.CompletedTask;
        }

        private void ExecuteAsync(object state)
        {
            _logger.LogInformation("Checking for unprocessed videos to generate thumbnails...");

            try
            {
                var unprocessedVideos = _videoService.GetUnprocessedVideos();

                foreach (var video in unprocessedVideos)
                {
                    // Simulate video processing by adding a delay.
                    Thread.Sleep(TimeSpan.FromSeconds(5));

                    // Simulate video processing logic (thumbnail generation).
                    // Replace this with your actual video processing implementation.
                    // For this example, we'll just log the processing action.
                    _logger.LogInformation($"Simulating video processing for video with ID: {video.Id}");

                    _videoService.MarkAsProcessed(video.Id);
                    _logger.LogInformation($"Thumbnail generated for video with ID: {video.Id}");
                }

                _logger.LogInformation("Video processing completed.");
            }
            catch (Exception ex)
            {
                _logger.LogError($"Error processing videos: {ex.Message}");
            }
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("VideoProcessingService is stopping.");

            // Dispose the Timer when the service is stopped.
            _timer?.Change(Timeout.Infinite, 0);

            return Task.CompletedTask;
        }

        public void Dispose()
        {
            // Dispose the Timer when the service is disposed.
            _timer?.Dispose();
        }
    }
}

Step 5: Register the Services In the Startup.cs file, register the VideoProcessingService and VideoService as services in the dependency injection container.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using HostedService.Service;

namespace HostedService
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            // Add the hosted service to the DI container
            services.AddHostedService<VideoProcessingService>();

            // Register the video service
            services.AddSingleton<IVideoService, VideoService>();

            services.AddControllers();


        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseStaticFiles();
            app.UseRouting();

           
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
            });
        }

    }
}

Step 6: Test the Video Processing
Now that everything is set up, run the application, and send the POST request from Postman, the video details will be received by your API. The video processing service (VideoProcessingService) will automatically pick up the video and simulate the processing (thumbnail generation) as a background task.

Check the logs in your application output to see the processing status. The VideoProcessingService will log messages indicating the processing of videos.

using HostedService;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace IdentityServer.Demo;
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Conclusion:

In this blog post, we explored how to use HostedService in .NET Core to perform background processing tasks. We implemented a VideoProcessingService as a background task to simulate video processing by generating thumbnails for unprocessed videos. The VideoService helped manage the video entities and track their processing status.

Next Post Previous Post
No Comment
Add Comment
comment url