我在应用程序的配置/依赖注入方面遇到了一个大问题。
我有一个通过DI与AddSingleton添加的单例类,在其构造函数中有一个IRequestClient,它的作用域是因为busConfigurator.AddRequestClient()
它的作用与addscope相同。
当我启动应用程序时,它说无法使用作用域服务"MassTransit.IRequestClient"1[…][from singleton '…'.)">
这完全有道理。
最奇怪的是,我有另一个应用程序设置完全相同的方式,但它只是工作,我真的希望该类保持单例
我的同事和我花了一整天的时间试图找出这两个应用程序之间的差异,但它们在配置上几乎是相同的,所以我们很难理解为什么一个可以工作而另一个不能。
我不完全确定哪些细节对于更好地定义问题是重要的,所以请随时提问。
我们看到所有在互联网上试图找到一个解决方案,但它总是"改变单transient",但这不是一个选择,第一,因为它是一个单例,否则它不会理解在我们的应用程序,这是缓存大量的日期从我们的数据库所以我们不能到处收集大量的数据,第二个,因为第一个应用程序适用于单例,不是短暂的和我们想要保持这种方式
// This method is called in Main()
private static void ConfigureMassTransit(IServiceCollection services)
{
services.AddMassTransit(busConfigurators =>
{
busConfigurators.AddRequestClient<ICacheRepository>();
busConfigurators.AddConsumers(typeof(Program).GetTypeInfo().Assembly);
busConfigurators.UsingRabbitMq((context, cfg) =>
{
cfg.Host(new Uri($"rabbitmq://{Config.Settings.RabbitMq_Host}"), hostConfigurator =>
{
hostConfigurator.Username(Config.Settings.RabbitMq_User);
hostConfigurator.Password(Config.Settings.RabbitMq_Password);
});
cfg.ReceiveEndpoint("myApp", e =>
{
e.ConfigureConsumers(context);
});
});
});
// CacheRepository
public class CacheRepository : ICacheRepository
{
private readonly IClient Client;
public CacheRepository(ICacheRepository client, ILogger<CacheRepository> logger)
{
this.client = client;
this.logger = logger;
}
}
当一个依赖被限定作用域时,这意味着每个作用域都需要一个新的实例(通常是一个传入的HTTP请求或消息)。这意味着实例不应该被多个请求重用。
如果你有一个依赖于那个作用域依赖的单例,那么该单例将使用该依赖的一个实例(请求客户端)来创建。因为那个独生子"永生"它所包含的请求客户端的实例也是如此。
结果是请求客户端不应该在不同的范围内被重用,但现在可以了。一个实例永远使用。
一个可能的解决方案是修改依赖于该客户端的类,使其不需要是单例的。你提到它必须是单例的,因为它缓存数据。
如何缓存数据?它是通过在私有字段中存储数据来实现的吗?如果是这样,也许您可以将该字段设置为静态。现在,类实例不再被重用,但是这些字段在实例之间共享。(验证与这些字段的交互是线程安全的,如果它们可以被并发访问。)
或者如果有其他的缓存机制,你可以把它移到它自己的依赖项中,使它成为一个单例。
那么你的类可以被限定作用域。它将依赖于单例缓存,总是使用相同的实例。它还将取决于作用域请求客户端,为每个作用域使用一个新实例。
您可以注入IServiceProvider
,并在单例需要执行请求时创建一个作用域。这样,您就坚持了请求客户机的预期用途。
await using var scope = provider.CreateAsyncScope();
var client = scope.ServiceProvider.GetRequiredService<IRequestClient<T>>();
await client.GetResponse(...);