未在类库中实例化IMemoryCache

时间:2018-07-18 14:00:05

标签: c# caching asp.net-core dependency-injection

我对ASP.Net Core,C#,OOP,Javascript还是很陌生……基本上对于我目前正在使用的一切。最近几个月,我一直在阅读和学习,以便开始一个新的开发项目。 总而言之,我一直在稳步前进,但是遇到了IMemoryCache的问题,我无法真正解决这个问题(或者是使用DI吗?)。

我正在使用ASP.Net Core 2.0和VS2017。我有一个包含2个项目的解决方案,主要的ASP.Net Core MVC Web应用程序和.Net Core 2.0类库。

在类库中,我添加了一个要在其中使用缓存的类,因此我将IMemoryCache添加到了构造函数中。 要实例化该类,我还有另一个构造函数,该构造函数调用函数GetModelGuidAsync

public class MdsEntityCRUD
    {
        #region ClassConstruct

        private readonly IMemoryCache _cache;
        public MdsEntityCRUD(IMemoryCache cache)
        {
            _cache = cache;
        }

        public MdsEntityCRUD(ServiceClient client, string modelName, string entityName, string versionFlag)
        {
            this.client = client;
            this.ModelId = Task.Run(async () => await GetModelGuidAsync(modelName)).Result;
            this.EntityName = entityName;
            mdsWS.Version ver = Task.Run(async () => await GetVersionByPolicyAsync(client, VersionPolicy.Flag, versionFlag, this.ModelId)).Result;
            this.VersionId = ver.Identifier.Id;
        }

        public async Task<Guid> GetModelGuidAsync(string modelName)
        {
            Dictionary<string, Guid> modelNames;

            if (!_cache.TryGetValue("ModelNames", out modelNames) || !modelNames.ContainsKey(modelName))
            {
                modelNames = await GetModelNamesAsync();
                _cache.Set("ModelNames", modelNames, new MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60) });  // CFG
            }

            return modelNames[modelName];
        }

我已经在我的MVC项目的启动过程中将 services.AddMemoryCache(); 添加到ConfigureServices中。 我正在使用第二个构造函数从MVC项目中的Controller调用该类。 在运行时,我在if (!_cache.TryGetValue语句中收到错误。这些是“异常帮助器”中和异常窗口中显示的详细信息:

  

System.AggregateException HResult = 0x80131500 Message =一个或多个   发生错误。 (对象引用未设置为的实例   对象。)Source = System.Private.CoreLib StackTrace:位于   System.Threading.Tasks.Task.ThrowIfExceptional(Boolean   includeTaskCanceledExceptions)   System.Threading.Tasks.Task`1.GetResultCore(Boolean   waitCompletionNotification)   mdXmdsWS.MdsEntityCRUD..ctor(ServiceClient客户端,字符串modelName,   C:\ Users .. \ MdsEntityCRUD.cs:第59行的C:\ Users ..   MDS_MVC_Proto2.Controllers.DataExplorerController.EntityDataSource(DataManagerRequest   dmr),位于C:\ Users .. \ Controllers \ DataExplorerController.cs:第165行
  在Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object   目标,Object []参数)位于   Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext()

     

内部异常1:NullReferenceException:对象引用未设置为   对象的实例。

     

和from($ exception).InnerException

     
      
  • InnerException {System.NullReferenceException:对象引用未设置为对象的实例。在   Microsoft.Extensions.Caching.Memory.CacheExtensions.TryGetValue [TItem](IMemoryCache   缓存,对象键,TItem&值)   mdXmdsWS.MdsEntityCRUD.d__18.MoveNext()在   C:\ Users .. \ MdsEntityCRUD.cs:第84行   ---从上一个引发异常的位置开始的堆栈跟踪-   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()在   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务),位于System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()   在   mdXmdsWS.MdsEntityCRUD。<> c__DisplayClass16_0。<<-ctor> b__0> d.MoveNext()   在C:\ Users .. \ MdsEntityCRUD.cs:line 59} System.Exception   {System.NullReferenceException}
  •   

我不知道为什么会收到错误消息: 是否因为缓存在Class库中而不在MVC项目中? 是因为我试图在构造函数执行的函数中使用缓存吗? 我是否缺少某些配置?

渴望了解我要去哪里...

1 个答案:

答案 0 :(得分:0)

正如评论中指出的那样,依赖注入(DI)/控制反转(IoC)并不是魔术。从根本上讲,依赖注入只是意味着:“将对象A的实例传递给构造函数/方法,而不是new-将其放入构造函数/方法中”。

var service = new MyService(new MyDependency());

以上已经是依赖项注入,您将依赖项注入MyService,并且如果它接受基类/接口,则可以在不更改MyService的情况下更改其实现。这种方法通常称为“穷人DI”,没有任何外部工具或库。

然后有DI / IoC框架,它使这变得更容易,因此您不必自己new实例并将其注入服务中并为您管理对象的生存时间(应该每个类获得相同的实例(Singleton生存期)还是每次获得新的实例(瞬态生存期)?特定的一组类应该获取一个实例,而另一组获取另一个实例吗(作用域生存期))。

当使用带有框架或不带有框架的DI / IoC时,必须一直使用它。没有魔术。 IoC框架与上面的操作相同,new-创建一个类及其依赖项,并传递给它们的构造函数。

对于ASP.NET Core,控制器是通过内置的DI / IoC框架解析的,因此您可以注入任何注册的类(在Startup的ConfigureServices方法内部)。

在您的情况下,您显然是在使用第二个构造函数new来创建类,因此永远不会调用第一个构造函数,也永远不会设置_cache成员变量。当您尝试访问它时,您将得到可怕的NullReferenceException异常。您必须将依赖项添加到主构造函数中。

如果像您一样需要new一个类,则必须自己传递依赖项。在您的情况下,您需要将IMemoryCache注入控制器,然后将其传递给new版的类。

IMemoryCache缓存

public class MyController : Controller 
{
    private readonly MdsEntityCRUD mdsCrud;

    public MyController(IMemoryCache memoryCache) 
    {
        ServiceClient client = ...;
        mdsCrud = new MdsEntityCRUD(memoryCache, client, "modelname", "entityName", "v1");
    }
}

通过这种方式,您可以从Controller获取正确的IMemoryCache实例,然后将其传递给服务。

还有其他更优雅的方法来抽象它(使用ConfigureServices中的工厂类或工厂方法)来执行该操作,但是这超出了问题的范围。