Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net core ASP.NET核心-从标识缓存用户_Asp.net Core_Asp.net Identity_Entity Framework Core - Fatal编程技术网

Asp.net core ASP.NET核心-从标识缓存用户

Asp.net core ASP.NET核心-从标识缓存用户,asp.net-core,asp.net-identity,entity-framework-core,Asp.net Core,Asp.net Identity,Entity Framework Core,我正在使用标准的ASP.NET Core 2.1程序,我一直在考虑一个问题,即我的许多控制器方法都需要检索当前登录的用户 我注意到asp.net核心标识码使用一个DBSet来保存实体,对它的后续调用应该是从内存中的本地实体读取,而不是命中数据库,但似乎每次,我的代码需要一个DB read,因为我运行的是SQL Profiler,可以看到使用Id作为键运行的针对AspNetUsers的select查询 我知道有很多方法可以建立身份,而且随着版本的变化,身份也发生了变化,也许我做得不对,或者这里有一

我正在使用标准的ASP.NET Core 2.1程序,我一直在考虑一个问题,即我的许多控制器方法都需要检索当前登录的用户

我注意到asp.net核心标识码使用一个DBSet来保存实体,对它的后续调用应该是从内存中的本地实体读取,而不是命中数据库,但似乎每次,我的代码需要一个DB read,因为我运行的是SQL Profiler,可以看到使用Id作为键运行的针对AspNetUsers的select查询

我知道有很多方法可以建立身份,而且随着版本的变化,身份也发生了变化,也许我做得不对,或者这里有一个根本性的问题可以解决

我在startup.cs的ConfigureServices中设置了默认EF和标识存储:

services.AddDbContext<MyDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MyDBContext")));
services.AddIdentity<CustomIdentity, Models.Role>().AddDefaultTokenProviders().AddEntityFrameworkStores<MyDBContext>();
在标识码中,该方法似乎调用了UserStore FindByIdAsync方法,该方法在用户的DBSet上调用FindAsync。 报告说:


那么这里可能出了什么问题,有什么建议说明为什么ASP.NET Core在Userstore中的EF调用没有使用实体的本地数据库集吗?或者我的想法是错误的——每次调用控制器时,都会创建一个新的EF上下文

是的。每个请求都会实例化和销毁控制器,而不管发出请求的用户是相同的还是不同的。此外,上下文是请求范围的,因此它也会随着每个请求被实例化和销毁。如果在同一请求期间多次查询同一用户,它将尝试使用实体缓存进行后续查询,但您可能不会这样做

这就是说,这是一个过早优化的教科书示例。从数据库查询用户是一种非常快速的查询。它只是主键上的一个简单的select语句——就数据库查询而言,它不会变得更快或更简单。如果使用内存缓存,可能可以节省几毫秒的时间,但这需要考虑一整套因素,尤其要小心按用户分隔缓存,以免意外地为错误的用户引入错误的数据。更重要的是,内存缓存有很多问题,因此在生产中使用分布式缓存更为典型。一旦到了那里,缓存并不能真正为这样一个简单的查询买到任何东西,因为您只是从分布式缓存存储中获取它,而分布式缓存存储甚至可能是一个类似SQL Server的数据库,而不是您的数据库。只有缓存复杂和/或缓慢的查询才有意义,因为只有这样,从缓存中检索查询才会比再次访问数据库更快

长话短说,不要害怕查询数据库。这就是它的目的。它是您的数据源,因此如果您需要数据,请进行查询。一旦你的站点运行起来,你就可以分析或者监控性能,如果你发现查询速度慢或者过多,那么你就可以开始寻找优化的方法。在它真正成为问题之前不要担心它

有什么建议说明为什么ASP.NET Core在Userstore中的EF调用没有使用实体的本地数据库集

事实上,他是这样做的。引用msdn强调我的

异步查找具有给定主键值的实体。如果上下文中存在具有给定主键值的实体,则会立即返回该实体,而无需向存储发出请求。否则,将向存储区请求具有给定主键值的实体,如果找到该实体,则将其附加到上下文并返回。如果在上下文或存储中找不到实体,则返回null


因此,您无法避免对象的每个请求的初始读取。但同一请求中的后续读取不会查询存储。这是在疯狂的微观优化级别之外所能做的最好的了

ef dbcontext默认为作用域生存期,这意味着它将在每个请求结束时自动释放。你不应该试着把它放久一点。为什么您需要从数据库中获取如此多的用户?像用户电子邮件、id、名称和角色之类的内容可以是声明,这些声明被序列化并持久化到auth cookie中,因此如果您只需要这些内容,就不需要经常为用户访问数据库。您可以直接访问HttpContext.User,它是由auth中间件从auth cookie自动反序列化的claimsprincipal。@JoeAudette我很害怕,为什么要在Usermanager中读取显式DBset呢!我需要与用户一起存储各种属性,将它们全部转换为声明闻起来并不正确。如果您认为需要访问的内容与声明不匹配,则可以将它们缓存在内存或会话状态中,以避免在每次请求时命中数据库。一切都需要权衡。如果不知道您需要什么数据,我无法提供任何信息
关于部分或全部声明是否合理的建议。@JoeAudette只是与用户关联的自定义数据,它们确实需要缓存,我希望将它们与用户放在一起会更容易,因为我们有一个usermanager对象,而不是通常的EF调用。我必须想出一个缓存机制来代替这些。虽然分布式缓存在其他方面对我来说至少是数据库:-本地缓存对性能有很大的影响,这就是我在这里讨论的。我想我的问题是把用户数据和身份数据混在一起了,所以我应该把它分成两部分,并在某种会话中缓存用户数据。会话使用分布式缓存,所以再次,只需将一个DB查询切换到另一个DB查询。说真的,只需查询用户,不要担心它。@ChrisPratt这不是真的-会话选项之一默认选项是使用内存中的作为IDistributedCache存储。内存中的会话存储是默认的,因为它不需要配置。你不应该在生产中实际使用它。我们在这方面做了很多,但简单明了的事实是,您应该从数据库中查询用户。缓存、会话等都是多余的,如果你真的正确设置了你的应用程序,它们不会比直接查询用户更好。谢谢,但正如Joe Audette提醒我的那样,dbcontext的作用域是每个调用的,因此我对DBSet的唯一调用永远不会在下一个查询中出现。这是真的,但在每个请求中,调用FindAsync时都会使用本地DBSet
var user = await _userManager.GetUserAsync(HttpContext.User);
It’s important to note that two different ObjectContext instances will have two different ObjectStateManager instances, meaning that they have separate object caches.