我对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项目中? 是因为我试图在构造函数执行的函数中使用缓存吗? 我是否缺少某些配置?
渴望了解我要去哪里...
答案 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
中的工厂类或工厂方法)来执行该操作,但是这超出了问题的范围。