我正在尝试基于
IHostedService
实现电子邮件后台服务。
但我收到此错误:
System.AggregateException:“无法构造某些服务(验证服务描述符时出错”ServiceType:Business.Abstract.ICustomerService Lifetime:Scoped ImplementType:Business.Concrete.CustomerManager”:无法解析类型“DataAccess”的服务。尝试激活“DataAccess.Concrete.EntityFramework.EfCustomerDal”时出现“Concrete.EntityFramework.SqlContext”。)(验证服务描述符“ServiceType:DataAccess.Abstract.ICustomerDal 生命周期:作用域实现类型:DataAccess.Concrete.EntityFramework.EfCustomerDal”时出错:尝试激活“DataAccess.Concrete.EntityFramework.EfCustomerDal”时无法解析类型“DataAccess.Concrete.EntityFramework.SqlContext”的服务。)(验证服务描述符“ServiceType:Microsoft.Extensions.Hosting.IHostedService 生命周期时出错:Singleton” ImplementType:KodiksProject.API.Services.EmailBackgroundService':尝试激活'KodiksProject.API.Services.EmailBackgroundService'时无法解析类型'Business.Concrete.CustomerManager'的服务。)'
如何解决这个问题?
ICustomerService
:
public interface ICustomerService
{
IResult Add(Customer customer);
IResult Update(Customer customer);
IResult Delete(int id);
IDataResult<Customer> Get(int id);
IDataResult<List<Customer>> GetAll();
Task SendEmailsToCustomersAsync();
}
CustomerManager
:
public class CustomerManager : ICustomerService
{
ICustomerDal _customerDal;
private readonly IEmailService _emailService;
public CustomerManager(ICustomerDal customerDal, IEmailService emailService)
{
_customerDal = customerDal;
_emailService = emailService;
}
public IResult Add(Customer customer)
{
_customerDal.Add(customer);
return new SuccessResult();
}
public IResult Delete(int id)
{
_customerDal.Delete(id);
return new SuccessResult();
}
public IDataResult<Customer> Get(int id)
{
return new SuccessDataResult<Customer>(_customerDal.Get(c => c.CustomerId == id));
}
public IDataResult<List<Customer>> GetAll()
{
return new SuccessDataResult<List<Customer>>(_customerDal.GetAll());
}
public IResult Update(Customer customer)
{
_customerDal.Update(customer);
return new SuccessResult();
}
public async Task SendEmailsToCustomersAsync()
{
var customerEmails = await _customerDal.GetAllCustomerEmailsAsync();
var tasks = new List<Task>();
foreach (var email in customerEmails)
{
var task = _emailService.SendEmailAsync(email, "asdasas", "asasadasdasd");
tasks.Add(task);
}
await Task.WhenAll(tasks);
}
}
SqlContext
:
public class SqlContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"my connection string");
}
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Product> Products { get; set; }
}
EfCustomerDal
:
public class EfCustomerDal : EfEntityRepositoryBase<Customer, SqlContext>, ICustomerDal
{
private readonly SqlContext _context;
public EfCustomerDal(SqlContext context)
{
_context = context;
}
public async Task<List<string>> GetAllCustomerEmailsAsync()
{
var emails = await _context.Customers
.Select(c => c.Email)
.ToListAsync();
return emails;
}
}
ICustomerDal
:
public interface ICustomerDal : IEntityRepository<Customer>
{
Task<List<string>> GetAllCustomerEmailsAsync();
}
EmailService
:
public class EmailService : IEmailService
{
private readonly SmtpClient _smtpClient;
public EmailService()
{
_smtpClient = new SmtpClient("server")
{
Port = 465,
Credentials = new NetworkCredential("username", "password"),
EnableSsl = true,
};
}
public async Task SendEmailAsync(string to, string subject, string body)
{
var mailMessage = new MailMessage("username", to, subject, body);
await _smtpClient.SendMailAsync(mailMessage);
}
}
我尝试了一切,但无法解决这个问题。在我尝试与后台工作人员发送电子邮件之前,这是有效的。我看不出我的依赖注入或服务寿命有任何问题。
我被困在这里,不知道该怎么办。
你能帮我解决这个问题吗?
文档的在后台任务中使用范围服务对此进行了介绍。托管服务注册为单例,它们不应该(如果启用范围验证则不能)消耗范围依赖项。默认情况下,EF Core 上下文添加为单例(即通过
AddDbContext...
调用)。解决方案是注入 IServiceProvider
并用它来解决依赖关系。例如:
public class ConsumeScopedServiceHostedService : BackgroundService
{
private readonly ILogger<ConsumeScopedServiceHostedService> _logger;
private readonly IServiceProvider Services;
public ConsumeScopedServiceHostedService(IServiceProvider services, ILogger<ConsumeScopedServiceHostedService> logger)
{
Services = services;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Consume Scoped Service Hosted Service running.");
using var scope = Services.CreateScope();
var scopedProcessingService = scope.ServiceProvider
.GetRequiredService<IScopedProcessingService>();
await scopedProcessingService.DoWork(stoppingToken);
}
}
另请阅读:
这是因为您的 dbcontext 已被释放而发生的,要解决此问题,您可以在 EmailService 的 SendEmailAsync 方法中创建一个工作范围单元,然后它必须正常工作。这是使用后台服务时的普遍问题。