我有一个。net后台服务
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly ConvertService _convert;
public Worker(ILogger<Worker> logger, ConvertService convert)
{
_logger = logger;
_convert = convert;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await _convert.GetXML();
await Task.Delay(TimeSpan.FromHours(12), stoppingToken);
}
}
}
Program.cs
using Microsoft.EntityFrameworkCore;
using P1_APT_SUB;
using P1_APT_SUB.BusService;
using P1_APT_SUB.Persistence;
IHost host = Host.CreateDefaultBuilder(args)
.UseWindowsService(options =>
{
options.ServiceName = "APT";
})
.ConfigureServices((context,services) =>
{
services.AddHttpClient("auth", httpClient =>
{
});
services.AddHttpClient("ODM", httpClient =>
{
});
services.AddTransient<ConvertService>();
services.AddTransient<BusServiceClass>();
services.AddHostedService<Worker>();
services.AddDbContext<DataContext>(
options =>
{
options.UseSqlServer();
});
})
.Build();
await host.RunAsync();
ConvertService.cs
这里是创建作用域并将其传递给方法,如GetST()
和httpCLient是ok
using Newtonsoft.Json.Linq;
using System.Xml.Linq;
using P1_APT_SUB.BusService;
using P1_APT_SUB.Persistence;
using P1_APT_SUB.Entities;
namespace P1_APT_SUB
{
public class ConvertService
{
private readonly IHttpClientFactory? _httpClientFactory;
private readonly IConfiguration? _config;
private readonly DataContext _dataContext;
private readonly BusServiceClass _busService;
static public string? sites;
public ConvertService(IConfiguration config, IServiceScopeFactory factory)
{
_httpClientFactory = factory.CreateScope().ServiceProvider.GetRequiredService<IHttpClientFactory>();
_config = config;
_dataContext = factory.CreateScope().ServiceProvider.GetRequiredService<DataContext>();
_busService = factory.CreateScope().ServiceProvider.GetRequiredService<BusServiceClass>();
}
public ConvertService()
{
}
public async Task GetXML()
{
var data = await new Domains().GetST(_httpClientFactory, _config);
sites = await new Domains().GetSD(_httpClientFactory, _config);
}
}}
}
Domains.cs
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace P1_APT_SUB
{
public class Domains
{
public string subjects;
public string sites;
private readonly IHttpClientFactory _httpClientFactory;
public async Task<string> GetST(IHttpClientFactory _httpClientFactory, IConfiguration _config)
{
var accessToken = await Authorization.GetAccessToken(_httpClientFactory);
var httpClient = _httpClientFactory.CreateClient("ODM");
httpClient.DefaultRequestHeaders.Add("X-ACCESS-TOKEN", accessToken);
var httpResponseMessage = await httpClient.GetAsync();
if (httpResponseMessage.IsSuccessStatusCode)
{
var contentStream =
await httpResponseMessage.Content.ReadAsStringAsync();
subjects = contentStream;
}
return subjects;
}
public async Task<string> GetSD(IHttpClientFactory _httpClientFactory, IConfiguration _config)
{
var accessToken = await Authorization.GetAccessToken(_httpClientFactory);
var httpClient = _httpClientFactory.CreateClient("ODM");
httpClient.DefaultRequestHeaders.Add("X-ACCESS-TOKEN", accessToken);
var httpResponseMessage = await httpClient.GetAsync();
if (httpResponseMessage.IsSuccessStatusCode)
{
var contentssStream =
await httpResponseMessage.Content.ReadAsStringAsync();
sites = contentssStream;
}
return sites;
}
}
}
但是当我想直接在Domains
中DI/创建范围时,就像下面的httpCLient是空的。这与后台服务是单例的有关,我认为是这样吗?
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace P1_APT_SUB
{
public class Domains
{
public string subjects;
private readonly IHttpClientFactory _httpClientFactory;
public Domains(IServiceScopeFactory factory)
{
this.subjects = subjects;
this.sites = sites;
_httpClientFactory = factory.CreateScope().ServiceProvider.GetRequiredService<IHttpClientFactory>();
}
public Domains()
{
}
public async Task<string> GetSubjects(IConfiguration _config)
{
var accessToken = await Authorization.GetAccessToken(**_httpClientFactory**);
var httpClient = _httpClientFactory.CreateClient("ODM");
httpClient.DefaultRequestHeaders.Add("X-ACCESS-TOKEN", accessToken);
var httpResponseMessage = await httpClient.GetAsync();
if (httpResponseMessage.IsSuccessStatusCode)
{
var contentStream =
await httpResponseMessage.Content.ReadAsStringAsync();
subjects = contentStream;
}
return subjects;
}
}
}
编辑
关于DataContext是单例的,我认为这将做的工作?就像using
对Dispose()
的称呼一样?有时不
await using var scope = _factory.CreateAsyncScope(); var context = scope.ServiceProvider.GetRequiredService<DataContext>(); List<Subject>? currentData = context.Subjects.ToList();
将domain作为服务添加到ConvertService中
services.AddTransient<Domains>();
public ConvertService(IConfiguration config, IServiceScopeFactory factory, Domains domains)
{
_httpClientFactory = factory.CreateScope().ServiceProvider.GetRequiredService<IHttpClientFactory>();
_config = config;
_domains = domains;
_factory = factory;
_busService = factory.CreateScope().ServiceProvider.GetRequiredService<BusServiceClass>();
}
现在我可以在Domains
中DI IServiceScopeFactory而不需要从Convert
问题是你的构造函数:我假设Domains
对象将由DI创建,但你通过使用默认构造函数手动创建它:
public Domains(IServiceScopeFactory factory)
{
this.subjects = subjects;
this.sites = sites;
_httpClientFactory = factory.CreateScope().ServiceProvider.GetRequiredService<IHttpClientFactory>();
}
public Domains()
{
}
当你用new Domains()
调用createDomains
实例时,所有成员都将是null
,因为无参数构造函数不做任何事情。
要解决这个问题,必须调用Domains(IServiceScopeFactory)
构造函数。
最简单的方法是将ConverService
中的IServiceScopeFactory
实例存储在一个字段中,并将其传递给构造函数:
var data = await new Domains(_factory).GetST(_httpClientFactory, _config);
sites = await new Domains(_factory).GetSD(_httpClientFactory, _config);
然而,请看看作用域,因为你的代码目前将使你的DataContext
基本上是一个单例,因为你创建实例的方式。
编辑:原来的,但错误的答案:不应该在单例的构造函数中创建作用域。
将作用域视为其创建的服务的所有者。一旦范围由作用域创建的所有一次性服务也将被丢弃。
在构造函数中创建临时作用域,这些作用域可能在使用服务之前被GC处理。
你应该做的是在你的构造函数中注入IServiceScopeFactory
,并根据需要创建和处置你的服务范围:
// Create new scope and dispose after use
using var scope = _serviceScopeFactory.CreateScope();
// Resolve instances
var service = scope.ServiceProvider.GetRequiredService<TService>();
有关更多指南,请参阅https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines