Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF Core DBContext inside Net Core Worker Windows service

what I am trying to achieve is code a simple .net core background worker (.net core 3.1) where I write data to a SQL Server database (through EF Core 3.1) while this worker is running as a windows service.

When I run the below code from Visual Studio 2019, everything works, but when I publish (Target win-x64) and register the .exe as a service on my win10 machine, I get the following Exception:

Microsoft.Data.SqlClient is not supported on this platform.

Any thoughts on what is causing this and how to fix it?

Program.cs

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Soteria.Common.Database;

namespace Soteria.Service
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            var host = Host.CreateDefaultBuilder(args)
                .UseWindowsService()
                .ConfigureServices((hostContext, services) =>
                {
                    var optionsBuilder = new DbContextOptionsBuilder<SoteriaDbContext>();
                    optionsBuilder.UseSqlServer("Server=.\\SQLEXPRESS;Database=Soteria;Trusted_Connection=True;");//,
                    services.AddScoped<SoteriaDbContext>(s => new SoteriaDbContext(optionsBuilder.Options));

                    services.AddHostedService<Worker>();
                });

            return host;
        }
    }
}

Worker.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Soteria.Common.Database;
using Soteria.Common.Messaging;
using Soteria.Common.Models;

namespace Soteria.Service
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly IServiceScopeFactory _serviceScopeFactory;

        public Worker(ILogger<Worker> logger, IServiceScopeFactory serviceScopeFactory)
        {
            _logger = logger;
            _serviceScopeFactory = serviceScopeFactory;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                using var scope = _serviceScopeFactory.CreateScope();

                var dbContext = scope.ServiceProvider.GetRequiredService<SoteriaDbContext>();

                dbContext.Tests.Add(new Test() {Date = DateTime.Now});
                dbContext.SaveChanges();

                await Task.Delay(1000, stoppingToken);               
            }
        }  
    }
}

SoteriaDbContext.cs

using Microsoft.EntityFrameworkCore;
using Soteria.Common.Models;

namespace Soteria.Common.Database
{
    public class SoteriaDbContext: DbContext
    {
        public SoteriaDbContext(DbContextOptions<SoteriaDbContext> options)
            : base(options)
        {
        }

        public DbSet<Test> Tests { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {            
            modelBuilder.Entity<Test>().ToTable("Tests");
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.EnableSensitiveDataLogging(true);
        }
    }
}

Test.cs

using System;

namespace Soteria.Common.Models
{
    public class Test
    {
        public int? Id { get; set; }
        public DateTime Date { get; set; }
    }
}

Tests.sql

CREATE TABLE [dbo].[Tests]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY, 
    [Date] DATETIME NOT NULL
)
like image 803
Kenneth Avatar asked Jan 15 '20 10:01

Kenneth


People also ask

How does DbContext work in .NET Core?

A DbContext instance represents a session with the database and can be used to query and save instances of your entities. DbContext is a combination of the Unit Of Work and Repository patterns. Entity Framework Core does not support multiple parallel operations being run on the same DbContext instance.

Can I use EF in .NET Core?

Entity Framework is an Object/Relational Mapping (O/RM) framework. It is an enhancement to ADO.NET that gives developers an automated mechanism for accessing & storing the data in the database. EF Core is intended to be used with . NET Core applications.

Which method is used for adding DbContext class as service?

The AddDbContext extension method registers DbContext types with a scoped lifetime by default.

Should DbContext be transient or scoped?

But if you use other injected services, with "transient" on the DBContext, every service gets his own instance of it. In order to avoid that you should always use "scoped" on the DBContext. Save this answer.


1 Answers

I had to install the published sources of the win-x64 folder, and not the "publish" folder to make this actually work. This even though my target runtime was win-x64, which would have led me to expect the published result would be in the "publish" folder.

Release folder structure and confusing publish folder

like image 189
Kenneth Avatar answered Oct 01 '22 16:10

Kenneth