In this post:
- Create a windows service project with appsetting.json, connect database, and dependency injection.
- Create and install windows service.
- Create a new project.
- Select Worker Service. Select Next.
- Provide a project name in the Project name field or accept the default project name. Select Create.
- In the Create a new Worker service dialog, select Create.
You the project is created you will see a file named Worker.cs.
DoWork method is where you going to implement your service logic.
private async Task DoWork(CancellationToken stoppingToken)
But because Worker implemented BackgroundService so you can not inject singletons into the worker directly. So the workaround way is to implement DoWork method in a different service and use IServiceProvider to create a scope to put it back in Worker.cs. It's a little hard to understand right now but you will understand when you see the code.
Create an interface IWorkerScope implemented DoWork method.
Create a class named WorkerScope implemented IWorkerScope.
WokerScope is now where you going to implement your service logic and you can freely use dependency injection here.
At this point, you should have these 3 files: Woker.cs, IWorkerScope.cs and WorkerScope.cs.
This is my worker class, you can see I use IServiceProvider to create a scope inside the DoWork method so now the DoWork is actually defined in WorkerScope.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace myService
{
public class Worker: BackgroundService
{
private readonly IServiceProvider _services;
public Worker(IServiceProvider services)
{
_services = services;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await DoWork(stoppingToken);
}
private async Task DoWork(CancellationToken stoppingToken)
{
using var scope = _services.CreateScope();
var scopedProcessingService =
scope.ServiceProvider
.GetRequiredService<IWorkerScope>();
await scopedProcessingService.DoWork(stoppingToken);
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
await base.StopAsync(stoppingToken);
}
}
}
This is the IWorkerScope interface:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace myService
{
internal interface IWorkerScope
{
Task DoWork(CancellationToken stoppingToken);
}
}
This is the WorkerScope class:
As you can see I injected ApiService, in your case, it might be services to get data from a database or some services.
Here I just write current datetime to a file named resutl.txt. You can do whatever you want here.
The delay time decides how frequently you want your service to run.
Here my service runs every 1 second.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace myService
{
internal class WorkerScope: IWorkerScope
{
private ApiService _apiService;
public WorkerScope(ApiService apiService) {
_apiService = apiService;
}
public async Task DoWork(CancellationToken stoppingToken) {
while (!stoppingToken.IsCancellationRequested)
{
// write current datetime to result.txt every 1 second.
using (StreamWriter writer = File.CreateText("result.txt"))
{
writer.WriteLine(_apiService.GetData().ToString());
}
await Task.Delay(1000, stoppingToken);
}
}
}
}
Another important part is your Program.cs. This is where you add your database connections, services,.. just like the startup.cs in a normal web project.
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using myService.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace myService
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
builder
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
})
.ConfigureServices((hostContext, services) =>
{
// add your connnections, I use Postgresql you can use other database like SQL server, it should work the same.
// if you using Postgresql as well, you need to install Npgsql.EntityFrameworkCore.PostgreSQL in nuget.
services.AddDbContext<ApplicationDbContext>((IServiceProvider serviceProvider, DbContextOptionsBuilder options) =>
options.UseNpgsql(hostContext.Configuration.GetSection("AppConfig:ConnectionString").Value)
);
//add your services like repositories, APIs, services.
services.AddScoped<ApiService>();
//add the worker.
services.AddScoped<IWorkerScope, WorkerScope>();
services.AddHostedService<Worker>();
}).UseWindowsService();
}
}
Don't forget to UseWindowsService(); // (install Microsoft.Extensions.Hosting.WindowsServices in nuget);
Now run your service you should see the datetime written in result.txt changing every 1 second.
So that's your service. Next, I will show you how to install your service as a windows service
Create and install windows service.
First, you need to build your project.
Right-click on your project, select Publish, select Folder, select Next, choose your folder location and click Finish. Click Publish.
To create a windows service:
Run Command prompt as administrator.
Run this command:
sc create YourServiceName BinPath= "_path_to_your_service_folder\myService.exe"
Now right-click on the taskbar, select Task Manager, select tab Services and verify if your service is created.
If you want to delete the service use
sc delete YourServiceName
It depends on your Current root path, result.txt might be created inside your service folder or C:\Windows\System32.
In some cases when you use Environment variables or do anything related to user permission, you might want to config permission by right-clicking on the service, select Open services, find your service, right-click, select Properties, in tab Log on, select Choose this account and browse the account you want to use.
Comments
Post a Comment