C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制
在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.Net Core的缓存机制。
关于.Net Core的缓存,官方有三种实现:
1.In Memory Caching 我理解是在内容中实现,这种方法适用于单服务器的生产环境。
2.a Distributed Cache 分部式缓存实现。
3.Response Cache 这种方式我理解为客户端缓存。
今天我只用了第一种实现方法,内存中缓存,之所以用这种方法我是觉得我这里用缓存的初衷是为了减少访问数据库的次数,而把访问数据库频率最高的数据转变为对象而放在缓存里。对于分部式说实话目前我也只是听说和了解原理,而没有做过实现,这里先不谈它。
微软官方提供的实现In Memory Caching 方法时有一个微软标准的示例,GitHub地址是 在这里
示例是用中间件实现的,经过一番学习,用示例里面提到的方法通过中间件实现了缓存,但怎么用到Controller里成了一个难题,也可能是我对中间件的了解不够深入吧!反正我是不知道该怎么办了!无耐之下,还是仔细研究了一下代码发现在中间件里面对缓存的调用(包括设置和取出)其实只在下面这段代码里实现:
if(!_memoryCache.TryGetValue(cacheKey, out greeting))
{
// fetch the value from the source
greeting = _greetingService.Greet("world"); // store in the cache
_memoryCache.Set(cacheKey, greeting,
new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes()));
_logger.LogInformation($"{cacheKey} updated from source.");
}
else
{
_logger.LogInformation($"{cacheKey} retrieved from cache.");
}
也就是 _memoryCache.TryGetValue(cacheKey, out greeting)这一段负责从缓存中取出缓存内容;而_memoryCache.Set(cacheKey, greeting, new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(1)));这个方法调用是把数据放到缓存里面的!
知道了这些以后就着手改造我的程序了:
1.创建IAdminTreeService.cs接口类:
public interface IAdminTreeService
{
/// <summary>
/// 全部节点数据树
/// </summary>
AdminUserTree GetAllTreeData { get; }
}
2.创建服务AdminTreeServices.cs,用于实现从数据库中取出管理菜单数据,用服务方式实现这种方式还是借鉴了官方示例的实现方式,这种实现是有其道理的。道理自己琢磨吧,最起码有得用接口统一。不再啰嗦直接代码:
public class AdminTreeServices:IAdminTreeService
{
/// <summary>
/// EF数据访问配置
/// </summary>
private readonly ApplicationDbContext _basecontext; public AdminTreeServices(ApplicationDbContext context)
{
_basecontext = context;
} /// <summary>
/// 建立无限极节点树-管理菜单
/// </summary>
/// <returns></returns>
public AdminUserTree GetAllTreeData
{
get
{
AdminUserTree result = new AdminUserTree();
//初始化一个节点做为根节点
result.NodeID = ;
result.Text = "管理员菜单";
result.Url = "";
result.ParentID = -;
result.Location = "";
result.OrderID = ;
result.Comment = "来源为数据库";
result.ImageUrl = "";
result.PermissionID = ;
result.Level = ;
result.ChildNumberl = ;
//把根节点传递给递归方法去创建子节点
result.ChildNode = BuildMenuTree(result, -);
return result; } } /// <summary>
/// 递归创建子节点方法
/// </summary>
/// <param name="node">要为其分配子节点的父级节点</param>
/// <param name="levelID">层级关系</param>
/// <returns></returns>
protected List<AdminUserTree> BuildMenuTree(AdminUserTree node, int levelID)
{
var listtree = _basecontext.Admintree; //从数据库中取出node节点的全部子节点 条件:m.ParentID==node.NodeID
List<AdminUserTree> lt = listtree.Where(m => m.ParentID == node.NodeID)
.Select(m => new AdminUserTree()
{
NodeID = m.NodeID
,
Text = m.Text
,
Url = m.Url
,
ParentID = m.ParentID
,
Location = m.Location
,
OrderID = m.OrderID
,
Comment = m.Comment
,
ImageUrl = m.ImageUrl
,
PermissionID = m.PermissionID
})
.ToList(); if (lt != null)
{
//节点深度
node.Level = levelID + ;
//子节点数量,便于前端递归输出时调用
node.ChildNumberl = lt.Count;
for (int i = ; i < lt.Count; i++)
{
//递归调用创建子节点
lt[i].ChildNode = BuildMenuTree(lt[i], node.Level);
}
return lt; }
else
{
return null;
} } }
AdminTreeServices
3.管理页面基类 AdminBase.cs:
public class AdminBase: Controller
{
/// <summary>
/// EF数据访问配置
/// </summary>
private readonly ApplicationDbContext _basecontext;
private readonly IAdminTreeService _adminTreeService;
private readonly ILogger<AdminUserTree> _logger;
private readonly IMemoryCache _memoryCache; /// <summary>
/// 管理菜单 这里是基数,声明为属性以便控制器里面可以用到
/// </summary>
public AdminUserTree leftMenu { get; set; } public AdminBase(ApplicationDbContext context,
IMemoryCache memoryCache,
ILogger<AdminUserTree> logger,
IAdminTreeService adminTreeService)
{
_basecontext = context;
//初始化无限极分类管理菜单
_logger = logger;
_adminTreeService = adminTreeService;
_memoryCache = memoryCache;
leftMenu = GetAdminTreeByCache();
} /// <summary>
/// 从缓存中读取节点树
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
public AdminUserTree GetAdminTreeByCache()
{
string cacheKey = "AdminTree-Base";
AdminUserTree adminTree; //获取缓存内容的一种方式
// greeting = _memoryCache.Get(cacheKey) as string; //另一种获取缓存内容的方式,
// alternately, TryGet returns true if the cache entry was found
if (!_memoryCache.TryGetValue(cacheKey, out adminTree))
{
//缓存中不存在该内容,从数据接口中通过访问数据库获取。
adminTree = _adminTreeService.GetAllTreeData; // 绝对过期时间方法,在设置缓存时3分钟后过期
//_memoryCache.Set(cacheKey, adminTree,
// new MemoryCacheEntryOptions()
// .SetAbsoluteExpiration(TimeSpan.FromMinutes(3)));
//相对过期时间方法,相对于最后一次调用后3分钟过期
_memoryCache.Set(cacheKey, adminTree,
new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromMinutes()));
//记录日志
_logger.LogInformation($"{cacheKey} From Data."+DateTime.Now.AddMinutes().ToString());
}
else
{
//记录日志,这里表示当前数据是从缓存中读取的。
_logger.LogInformation($"{cacheKey} From Cacha."+DateTime.Now.ToString());
} return adminTree; }
}
AdminBase
4.最后不要忘记了在Startup.cs中加入以下代码 :
public void ConfigureServices(IServiceCollection services)
{
…………
services.AddMemoryCache(); services.AddTransient<IAdminTreeService, AdminTreeServices>();
}
在这里基本就实现了通过缓存读取数据了!至于Controller中的实现没有变化请参考我的上篇随笔:
C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现
为了方便阅读这里再放一遍菜单节点类代码:
/// <summary>
/// 无限极节点类
/// </summary>
public class AdminUserTree
{
/// <summary>
/// 节点信息
/// </summary>
public int NodeID { get; set; }
/// <summary>
/// 节点名称
/// </summary>
public string Text { get; set; }
/// <summary>
/// 父节点ID
/// </summary>
public int ParentID { get; set; }
/// <summary>
/// 对应的链接地址
/// </summary>
public string Url { get; set; }
public int? PermissionID { get; set; }
public int? OrderID { get; set; }
public string Location { get; set; }
public string Comment { get; set; }
public string ImageUrl { get; set; }
/// <summary>
/// 层级
/// </summary>
public int Level { get; set; }
/// <summary>
/// 子节点数目(很重要)
/// </summary>
public int ChildNumberl { get; set; } /// <summary>
/// 子节点 (子节点是一个List)这种用法叫什么?
/// </summary>
public List<AdminUserTree> ChildNode { get; set; }
}
最后把运行时日志截图放出来:
首次访问:

上面有很多的数据库访问语句,日志提示数据来源与数据库
再次访问:

这里就是直接从缓存中读取出来的内容了!
好了今天的内容就写到这里。
按照先前的计划,下一步该研究一下用户及权限的内容了,这次我打算研究一下 ASP.NET Identity 身份验证和基于角色的授权,网上有很多相关的资料了,可我还是没有看明白怎么和我实际的项目相结合。估计要花几天时间了!
C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制的更多相关文章
- C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现
今天做一个管理后台菜单,想着要用无限极分类,记得园子里还是什么地方见过这种写法,可今天找了半天也没找到,没办法静下心来自己写了: 首先创建节点类(我给它取名:AdminUserTree): /// & ...
- sqlalchemy tree 树形分类 无限极分类的管理。预排序树,左右值树。sqlalchemy-mptt
简介: 无限极分类是一种比较常见的数据格式,生成组织结构,生成商品分类信息,权限管理当中的细节权限设置,都离不开无限极分类的管理. 常见的有链表式,即有一个Pid指向上级的ID,以此来设置结构.写的时 ...
- 无限极分类php实现—查子孙树、家谱树
1.本文更新日期:2018/05/20 , 亲测可用,在原有基础上进行增强和 详细化 . 2.面包屑导航 和 子孙树 效果图如下: 3.代码: <?php // 无限级分类中,查家谱树(面包屑导 ...
- js实现无限极分类
转载注明出处!!! 转载注明出处!!! 转载注明出处!!! 因为要实现部门通讯录,后台传来的数据是直接从数据库里拿的部门表,所以没有层级分类,只有parentId表示从属关系,所以分类的事情就交给我来 ...
- 夺命雷公狗ThinkPHP项目之----企业网站8之栏目的添加完善(无限极分类的完成)
我们刚才只是完成了添加的一部分,但是我们的上级分类也不能永远都是只有一个死的嘛,所以我们需要对她进行修改: 我们先将add方法里面的数据查出来再说: 然后在模板页进行遍历: 展示效果如下所示: 虽然是 ...
- DotNet菜鸟入门之无限极分类(一)设计篇
写这个教程的原因,是因为,无限极分类,在许多项目中,都用得到.而对于新手来说,不是很好理解,同时,操作上也有一些误区或者不当之处.所以我就斗胆,抛砖引玉一下,已一个常见的后台左侧频道树为例子,讲解一下 ...
- PHP实现菜单无限极分类
菜单数据 这里我们的菜单数据是临时数据, 没有从数据库中查询处理,数据基本和数据库中的的相似. 数据如下: $items = array( 1 => array('id' => 1, 'p ...
- php无限极分类以及递归(thinkphp)
php无限极分类: 无限极分类重点在于表的设计: 1在model中: class CatModel extends Model{ protected $cat = array(); public fu ...
- PHP无限极分类,多种方法|很简单,这里说的很详细,其它地方说的很不好懂
当你学习php无限极分类的时候,大家都觉得一个字"难"我也觉得很难,所以,现在都还在看,因为工作要用到,所以,就必须得研究研究. 到网上一搜php无限极分类,很多,但好多都是一 ...
随机推荐
- Android5.1.1 - APK签名校验分析和修改源码绕过签名校验
Android5.1.1 - APK签名校验分析和修改源码绕过签名校验 作者:寻禹@阿里聚安全 APK签名校验分析 找到PackageParser类,该类在文件“frameworks/base/cor ...
- Unity3D游戏开发初探—3.初步了解U3D物理引擎
一.什么是物理引擎? 四个世纪前,物理学家牛顿发现了万有引力,并延伸出三大牛顿定理,为之后的物理学界的发展奠定了强大的理论基础.牛顿有句话是这么说的:“如果说我看得比较远的话,那是因为我站在巨人的肩膀 ...
- 探索c#之函数创建和闭包
阅读目录: 动态创建函数 匿名函数不足之处 理解c#中的闭包 闭包的优点 动态创建函数 大多数同学,都或多或少的使用过.回顾下c#中动态创建函数的进化: C# 1.0中: public delegat ...
- 几个常用Json组件的性能测试
上一篇文章中我已经介绍了JsonBuilder方案的整体思路以及一个版本的雏形代码,他现在已经是可以使用的了,但是因为是实时反射的,所以效率并不高. 鉴于几位博友对Json转换组件的性能有兴趣,我先放 ...
- yar框架使用笔记
Yar是什么 Yar是并行的RPC框架(Concurrent RPC framework),Laruence开发. 安装 下载地址:http://pecl.php.net/package/yar wi ...
- 开源WinForms界面开发框架Management Studio 选项卡文档 插件 Office 2007蓝色风格 后台线程
Management Studio是我在WinForms小项目开发过程中搭建起来的一个插件式结构的应用程序框架,因为简单灵活又容易扩展,现在将它开源供读者参考. 跑起来的效果图如下所示,具备选项卡式多 ...
- HighCharts从数据库中读取数据
1.index.js router.get('/', function(req, res, next) { res.render('index', { title: 'Express' }); }); ...
- Routing 功能概述 - 每天5分钟玩转 OpenStack(98)
路由服务(Routing)提供跨 subnet 互联互通功能. 例如前面我们搭建了实验环境: cirros-vm1 172.16.100.3 vlan100 cirros-vm ...
- Markdown编辑器入门
欢迎使用博客园的Markdown编辑器 前言 今天早上起来在Ubuntu下操作,所以不能使用Windows Live Writer.所以就直接使用博客园的后台编辑器,开始以为博客园出错了,怎么编辑都没 ...
- SubSonic3.0.0.4.2源码包与调用Dll
================================================================ 名 称:SubSonic插件版 本:3.0.0.4.2最后 ...