注销器的另1个用途是: 通过触发器(EventPublisher)的实例,调用继承于注销器接口的指定具体实现类(StateCacheEventConsumer)中的方法(HandleEventAsync),来删除Redis中的缓存的省/直辖市的所有实例及其键之后,重新把数据库中省/直辖市所有数据更新加载到Redis的缓存中,从而达到立即把最新的数据在页面上进行渲染显示的目的。
1 StateAddEvent
using Linkage.Domain.Directory;
namespace Linkage.Events
{
/// <summary>
/// 【省/直辖市添加触发--类】
/// 摘要:
/// 通过该构造方法中的参数实例,来实例化该类中的同类型属性成员。
/// </summary>
public class StateAddEvent
{
#region 变量--拷贝构造方法
/// <param name="stateIntance">省/直辖市实体的1个指定实例。</param>
/// <summary>
/// 【拷贝构造方法】
/// </summary
/// <remarks>
/// 摘要:
/// 通过该构造方法中的参数实例,来实例化该类中的同类型属性成员。
/// </remarks>
public StateAddEvent(State stateIntance)
{
StateIntance = stateIntance;
}
#endregion
#region 属性
/// <summary>
/// 【单个省/直辖市】
/// <remarks>
/// 摘要:
/// 获取/设置省/直辖市实体的1个指定实例。
/// </remarks>
/// </summary>
public State StateIntance { get; }
#endregion
}
}
2 StateCacheEventConsumer
using Linkage.Events;
using Microsoft.Extensions.Caching.Distributed;
namespace Linkage.Caching
{
/// <summary>
/// 【省/直辖市注销器--类】
/// 摘要:
/// 在执行省/直辖市的插入操作之后,通过触发器实例,调用当前类中的方法(HandleEventAsync),来删除Redis中的缓存的省/直辖市的所有实例及其键之后,
/// 重新把数据库中省/直辖市所有数据更新加载到Redis的缓存中,从而达到立即把最新的数据在页面上进行渲染显示的目的。
/// </summary>
public class StateCacheEventConsumer : IConsumer<StateAddEvent>
{
#region 变量--拷贝构造方法
private readonly IDistributedCache _distributedCache;
public StateCacheEventConsumer(IDistributedCache distributedCache)
{
_distributedCache = distributedCache;
}
#endregion
#region 方法
/// <param name="eventMessage">省/直辖插入类的1个指定实例。</param>
/// <summary>
/// 【异步触发句柄】
/// <remarks>
/// 摘要:
/// 在执行省/直辖市的插入操作之后,通过触发器实例,调用当前方法,来删除Redis中的缓存的省/直辖市的所有实例及其键之后,
/// 重新把数据库中省/直辖市所有数据更新加载到Redis的缓存中,从而达到立即把最新的数据在页面上进行渲染显示的目的。
/// </remarks>
/// </summary>
public async Task HandleEventAsync(StateAddEvent eventMessage)
{
await _distributedCache.RemoveAsync("StateAll");
}
#endregion
}
}
3 CachingConsumerController
using Linkage.Data;
using Linkage.Domain.Directory;
using Linkage.Events;
using Linkage.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;
namespace Linkage.Controllers
{
public class CachingConsumerController : Controller
{
private readonly EFCoreContext _context;
private readonly IDistributedCache _distributedCache;
private readonly IEventPublisher _eventPublisher;
public CachingConsumerController(
EFCoreContext context,
IDistributedCache distributedCache,
IEventPublisher eventPublisher)
{
_context = context;
_distributedCache = distributedCache;
_eventPublisher = eventPublisher;
}
public async Task<IActionResult> Index()
{
StateModel _stateModel = new StateModel();
if (await _distributedCache.GetStringAsync("StateAll") == null)
{
await _distributedCache.SetStringAsync("StateAll",
JsonConvert.SerializeObject(await _context.StateDbSet.ToListAsync()),
new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(300) });
}
_stateModel.StateList = JsonConvert.DeserializeObject<List<State>>(await _distributedCache.GetStringAsync("StateAll"));
return View(_stateModel);
}
[HttpPost]
public async Task<IActionResult> RelayRenderAjax(StateModel stateModel)
{
State _state = new State();
_state.Name = stateModel.Name;
await _context.StateDbSet.AddAsync(_state);
await _context.SaveChangesAsync();
return Json(true);
}
[HttpPost]
public async Task<IActionResult> PromptlyRenderAjax(StateModel stateModel)
{
State _state = new State();
_state.Name = stateModel.Name;
await _context.StateDbSet.AddAsync(_state);
await _context.SaveChangesAsync();
//通过触发器实例,调用继承于注销器接口的指定具体实现类(StateCacheEventConsumer)中的方法(HandleEventAsync),来删除Redis中的缓存的省/直辖市的所有实例及其键之后,
//重新把数据库中省/直辖市所有数据更新加载到Redis的缓存中,从而达到立即把最新的数据在页面上进行渲染显示的目的。
await _eventPublisher.PublishAsync(new StateAddEvent(_state));
return Json(true);
}
}
}
4 CachingConsumer\Index.cshtml
@model Linkage.Models.StateModel
@{
ViewData["Title"] = "注销器注销缓存数据";
}
<div class="row">
<div class="col-md-12">
<form id="AddState">
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group text-center col-12 mt-3">
<button type="button" id="RelayRender" class="btn btn-dark me-5">
页面在<span class="fw-bolder text-danger">【延时5分钟后】</span>才能渲染显示添加数据
</button>
<button type="button" id="PromptlyRender" class="btn btn-dark">
页面在<span class="fw-bolder text-success">【添加后立即】</span>渲染显示添加数据
</button>
</div>
</form>
</div>
</div>
<div id="remainTime" class="text-danger text-center fw-bolder fs-2"></div>
<div class="row mt-3">
<table class="table">
<thead>
<tr>
<th scope="col">编号</th>
<th scope="col">省/直辖市</th>
</tr>
</thead>
<tbody>
@{
if (Model.StateList == null || Model.StateList.Count <= 0)
{
<tr>
<td colspan="2"><h1 class="text-danger text-center">暂无数据</h1></td>
</tr>
}
else
{
foreach (var item in Model.StateList)
{
<tr>
<td>@item.Id</td>
<td>@item.Name</td>
</tr>
}
}
}
</tbody>
</table>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script type="text/javascript">
var SysSecond;
var InterValObj;
$(document).ready(function () {
SysSecond = 330; //这里获取倒计时的起始时间
InterValObj = window.setInterval(SetRemainTime, 1000); //间隔函数,1秒执行
});
//将时间减去1秒,计算天、时、分、秒
function SetRemainTime() {
if (SysSecond > 0) {
SysSecond = SysSecond - 1;
var second = Math.floor(SysSecond % 60); // 计算秒
var minite = Math.floor((SysSecond / 60) % 60); //计算分
var hour = Math.floor((SysSecond / 3600) % 24); //计算小时
var day = Math.floor((SysSecond / 3600) / 24); //计算天
var hourDiv = "<span id='hourSpan'>" + hour + "小时" + "</span>";
var dayDiv = "<span id='daySpan'>" + day + "天" + "</span>";
$("#remainTime").html(dayDiv + hourDiv + minite + "分" + second + "秒");
if (hour === 0) {//当不足1小时时隐藏小时
$('#hourSpan').css('display', 'none');
}
if (day === 0) {//当不足1天时隐藏天
$('#daySpan').css('display', 'none');
}
} else {//剩余时间小于或等于0的时候,就停止间隔函数
window.clearInterval(InterValObj);
if (SysSecond <= 0) {
window.location.href = "/CachingConsumer/Index";
}
//这里可以添加倒计时时间为0后需要执行的事件
// alert("时间为0");
}
}
// 页面在【延时5分钟后】才能渲染显示添加数据
$("#RelayRender").on("click", function () {
if ($("#Name").val() == "" || $("#Name").val() == null) {
alert("省/直辖市不能为空!");
return;
}
$.ajax({
url: "/CachingConsumer/RelayRenderAjax",
type: "POST",
datatype: "JSON",
cache: false, //禁用缓存。
data: $("#AddState").serialize(),
success: function (data) {
window.location.href = "/CachingConsumer/Index";
}
});
});
// 页面在【添加后立即】渲染显示添加数据
$("#PromptlyRender").on("click", function () {
if ($("#Name").val() == "" || $("#Name").val() == null) {
alert("省/直辖市不能为空!");
return;
}
$.ajax({
url: "/CachingConsumer/PromptlyRenderAjax",
type: "POST",
datatype: "JSON",
cache: false, //禁用缓存。
data: $("#AddState").serialize(),
success: function (data) {
window.location.href = "/CachingConsumer/Index";
}
});
});
</script>
}
对以上功能更为具体实现和注释见:221028_16Linkage(注销器移除缓存数据)。