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无限极分类,很多,但好多都是一 ...
随机推荐
- Servant:基于Web的IIS管理工具
Servant for IIS是个管理IIS的简单.自动化的Web管理工具.安装Servant的过程很简单,只要双击批处理文件Install Servant Service.bat,然后按照屏幕上的说 ...
- 在MySQL的InnoDB存储引擎中count(*)函数的优化
写这篇文章之前已经看过了很多数据库方面的优化内容,大部分都是加索引.使用事务.要什么select什么等等.然而,只是停留在阅读的层面上,很少有实践,因为没有遇到真实的项目,一切都是纸上谈兵.实践是检验 ...
- Linux 定时任务
200 ? "200px" : this.width)!important;} --> 介绍 本篇主要介绍Linux定时任务命令crontab的用法,crontab是定时任务 ...
- 抛开flash,自己开发实现C++ RTMP直播流播放器
抛开flash,自己开发实现C++ RTMP直播流播放器 众所周知,RTMP是以flash为客户端播放器的直播协议,主要应用在B/S形式的场景中.本人研究并用C++开发实现了RTMP直播流协议的播放器 ...
- JavaScript面试时候的坑洼沟洄——数据类型
前些日子写了篇关于最近找工作的一些感受的博客 找工作的一些感悟--前端小菜的成长,没想到得到了很多园友的共鸣,得到了很多鼓励,也有园友希望我分享一些笔试.面试的经验.我觉得分享一些笔试题没太多价值,对 ...
- Session中放错误提示JSP上获取
servlet中: message= "图片上传失败!"; request.setAttribute("message",message); JSP中运用一 ...
- TODO:Linux安装PHP MongoDB驱动
TODO:Linux安装PHP MongoDB驱动 PHP利于学习,使用广泛,主要适用于Web开发领域. MongoDB的主要目标是在键/值存储方式(提供了高性能和高度伸缩性)以及传统的RDBMS系统 ...
- 轻量级前端MVVM框架avalon - 执行流程2
接上一章 执行流程1 在这一大堆扫描绑定方法中应该会哪些实现? 首先我们看avalon能帮你做什么? 数据填充,比如表单的一些初始值,切换卡的各个面板的内容({{xxx}},{{xxx|html}}, ...
- Android NDK开发Hello Word!
在之前的博客中已经为大家介绍了,如何在win环境下配置DNK程序,本篇我将带大家实现一个简单的Hello jni程序,让大家真正感受一下NDK开发的魅力.这里我们选择使用C+JAVA开发Android ...
- jQuery源码 Ajax模块分析
写在前面: 先讲讲ajax中的相关函数,然后结合函数功能来具体分析源代码. 相关函数: >>ajax全局事件处理程序 .ajaxStart(handler) 注册一个ajaxStart事件 ...