在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.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实现之方法二:加入缓存机制的更多相关文章

  1. C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现

    今天做一个管理后台菜单,想着要用无限极分类,记得园子里还是什么地方见过这种写法,可今天找了半天也没找到,没办法静下心来自己写了: 首先创建节点类(我给它取名:AdminUserTree): /// & ...

  2. sqlalchemy tree 树形分类 无限极分类的管理。预排序树,左右值树。sqlalchemy-mptt

    简介: 无限极分类是一种比较常见的数据格式,生成组织结构,生成商品分类信息,权限管理当中的细节权限设置,都离不开无限极分类的管理. 常见的有链表式,即有一个Pid指向上级的ID,以此来设置结构.写的时 ...

  3. 无限极分类php实现—查子孙树、家谱树

    1.本文更新日期:2018/05/20 , 亲测可用,在原有基础上进行增强和 详细化 . 2.面包屑导航 和 子孙树 效果图如下: 3.代码: <?php // 无限级分类中,查家谱树(面包屑导 ...

  4. js实现无限极分类

    转载注明出处!!! 转载注明出处!!! 转载注明出处!!! 因为要实现部门通讯录,后台传来的数据是直接从数据库里拿的部门表,所以没有层级分类,只有parentId表示从属关系,所以分类的事情就交给我来 ...

  5. 夺命雷公狗ThinkPHP项目之----企业网站8之栏目的添加完善(无限极分类的完成)

    我们刚才只是完成了添加的一部分,但是我们的上级分类也不能永远都是只有一个死的嘛,所以我们需要对她进行修改: 我们先将add方法里面的数据查出来再说: 然后在模板页进行遍历: 展示效果如下所示: 虽然是 ...

  6. DotNet菜鸟入门之无限极分类(一)设计篇

    写这个教程的原因,是因为,无限极分类,在许多项目中,都用得到.而对于新手来说,不是很好理解,同时,操作上也有一些误区或者不当之处.所以我就斗胆,抛砖引玉一下,已一个常见的后台左侧频道树为例子,讲解一下 ...

  7. PHP实现菜单无限极分类

    菜单数据 这里我们的菜单数据是临时数据, 没有从数据库中查询处理,数据基本和数据库中的的相似. 数据如下: $items = array( 1 => array('id' => 1, 'p ...

  8. php无限极分类以及递归(thinkphp)

    php无限极分类: 无限极分类重点在于表的设计: 1在model中: class CatModel extends Model{ protected $cat = array(); public fu ...

  9. PHP无限极分类,多种方法|很简单,这里说的很详细,其它地方说的很不好懂

    当你学习php无限极分类的时候,大家都觉得一个字"难"我也觉得很难,所以,现在都还在看,因为工作要用到,所以,就必须得研究研究.   到网上一搜php无限极分类,很多,但好多都是一 ...

随机推荐

  1. Java NIO2:缓冲区

    什么是缓冲区 一个缓冲区对象是固定数量的数据的容器,其作用是一个存储器,或者分段运输区,在这里数据可被存储并在之后用于检索.缓冲区像前篇文章讨论的那样被写满和释放,对于每个非布尔原始数据类型都有一个缓 ...

  2. PYTHON黑帽编程1.5 使用WIRESHARK练习网络协议分析

    Python黑帽编程1.5  使用Wireshark练习网络协议分析 1.5.0.1  本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks At ...

  3. 到底应该选择那种Linux.NET的部署方式?

    当前部署Linux.NET环境的方式可谓是五花八门,既有传统的源码编译的方式.又有各式各样的一键安装脚本.还有绿色包安装方式,而随着Mono官方的新站上线,更增加了采用RPM包的部署方式.那对于一名L ...

  4. 再探.NET的PE文件结构(安全篇)

    一.开篇 首先写在前面,这篇文章源于个人的研究和探索,由于.NET有自己的反射机制,可以清楚的将源码反射出来,这样你的软件就很容易被破解,当然这篇文章不会说怎么样保护你的软件不被破解,相反是借用一个软 ...

  5. Generate input file for OVITO

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...

  6. TODO:软件升级的那些事

    TODO:软件升级的那些事 软件升级,指软件从低版本向高版本的更新.由于高版本常常修复低版本的部分BUG,所以经历了软件升级,一般都会比原版本的性能更好,得到优化的效果,用户也能有更好的体验. 最近常 ...

  7. [python] 安装numpy+scipy+matlotlib+scikit-learn及问题解决

    这篇文章主要讲述Python如何安装Numpy.Scipy.Matlotlib.Scikit-learn等库的过程及遇到的问题解决方法.最近安装这个真是一把泪啊,各种不兼容问题和报错,希望文章对你有所 ...

  8. 【Prince2是什么】PRINCE2认证之PRINCE2的思维结构

    前两讲我们介绍了PRINCE2衡量绩效的六大要素和四大管理步骤,今天我们继续进行PRINCE2思维结构的介绍. PRINCE2自身有一个非常强大且坚固的思维结构,这个结构有四大元素组成.分别是1原则, ...

  9. java中对final关键字的理解以及使用场景

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.

  10. Python学习路径及练手项目合集

    Python学习路径及练手项目合集 https://zhuanlan.zhihu.com/p/23561159