【问题标题】:Injecting scoped service from singleton service in .net core 2.1从.net core 2.1中的单例服务注入范围服务
【发布时间】:2018-10-25 06:53:30
【问题描述】:

我有一个缓存助手。当我将 CacheHelper 的依赖项添加到使用“AddScoped”启动时,它正在工作。但是,CacheHelper.cs 正在为每个请求运行。所以,我转换为“AddSingleton”,如下所示。但我犯了一个错误,就像这样: 无法使用单例“MyProject.Caching.ICacheHelper”中的范围服务“MyProject.DataAccess.IUnitOfWork”如何解决此问题?

启动.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
        services.AddScoped<IUnitOfWork, UnitOfWork>();
        services.AddScoped<IJwtHelper, JwtHelper>();
        services.AddScoped<IAuditHelper, AuditHelper>();
        services.TryAdd(ServiceDescriptor.Singleton<IMemoryCache, MemoryCache>());
        services.AddSingleton<ICacheHelper, CacheHelper>();
        services.AddMvc();

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }

CacheHelper.cs

public class CacheHelper : ICacheHelper
{
    private readonly IUnitOfWork unitOfWork;
    public IMemoryCache Cache { get; }

    public CacheHelper(IUnitOfWork unitOfWork, IMemoryCache cache)
    {
        this.unitOfWork = unitOfWork;
        Cache = cache;
    }

    public void SetCommonCacheItems()
    {
        var cities = unitOfWork.CityRepo.GetAll();
        Cache.Set("cities", cities);

        string obj;
        Cache.TryGetValue<string>("cities", out obj);
    }

    public string GetCities()
    {
        string obj;
        Cache.TryGetValue<string>("cities", out obj);

        return obj;
    }
}

【问题讨论】:

  • 值得您花时间阅读:dotnetcoretutorials.com/2018/03/20/…
  • Singleton 不能引用 Scoped 实例
  • 谢谢@JohnB。我现在读了你的帖子。在那篇文章中,它建议我将 unitOfWork 添加为单例。但是当我将 UnitOfWork 作为单例进行时,我的请求并没有发送到服务器。哪里会出错?

标签: c# asp.net-web-api asp.net-core .net-core


【解决方案1】:

你以前的方式是正确的。 ICacheHelper 应该而且必须有范围。

只是你的缓存实现是错误的。获取城市将被调用,它检查缓存。如果没有找到,它将获取数据并将其放入缓存中。

public class CacheHelper : ICacheHelper
{
    private readonly IUnitOfWork unitOfWork;
    public IMemoryCache Cache { get; }

    public CacheHelper(IUnitOfWork unitOfWork, IMemoryCache cache)
    {
        this.unitOfWork = unitOfWork;
        Cache = cache;
    }

    public string GetCities()
    {
        if(!Cache.TryGetValue<string>("cities", string out cities))
        {
            // not found in cache, obtain it
            cities = unitOfWork.CityRepo.GetAll();
            Cache.Set("cities", cities);
        }

        return cities;
    }
}

您不需要SetCommonCacheItems() 方法。重要的是IMemoryCache 是静态的,因为它将包含数据。由于数据库,UoW 必须限定范围,否则您会出现内存泄漏(尤其是在使用 EF Core 时,因为它缓存/跟踪实体)。

【讨论】:

  • 非常感谢@Tseng。在我的想法中,一切都必须是单例的,否则请求会变慢。所以,我尝试了单例。但我从您的回复中了解到,每项服务都没有任何缺点。是真的吗?
  • 一般来说,作用域是理想的方式,因为否则长期存在的服务将/可能持有未释放的内存,并且您的应用程序会继续使用越来越多的内存,直到它崩溃。类和它们的构造函数应该很快,如果你做了一些需要在构造函数中做很多工作的事情,那你就做错了。
  • 再次感谢@Tseng。这对我很有帮助。
  • 重点是,由于 EF Core 和其他东西的工作方式,您的 UoW 必须有范围,因此您不会保存任何东西,也不会通过使其成为单例来帮自己一个忙。 IMemoryCache 无论如何都是静态的。因此,当 CacheHelper 仅构造 UoW 时(如果尚未针对该请求并传入。CacheHelper 构造函数除了分配它什么都不做,所以它的速度非常快并且 IMemory 缓存已经存在,所以只有它的引用被传递
猜你喜欢
  • 2019-10-22
  • 1970-01-01
  • 2020-08-05
  • 2019-07-15
  • 1970-01-01
  • 2017-03-20
  • 2019-06-21
  • 2018-08-07
  • 1970-01-01
相关资源
最近更新 更多