使用.NetCore自带的后台作业,出入队简单模拟生产者消费者处理请求响应的数据
环境:Core:3.1的项目
说明:由于该方案为个人测试项目,重启时队列中的部分数据很可能会丢失,
对数据有要求的该方案不适用,不能照搬需要持久化处理,
另外发布到Linux Docker中通常不会自动回收,但是发布到IIS中需要简单设置不回收即可!!! 如下截图:
在IIS中找到这个站点所用的程序池,点击 高级设置。。。 回收——固定时间间隔 修改为 0
回收——虚拟/专用内存限制 修改为 0
进程模型——闲置超时 修改为 0
1:先来看效果
1.1:操作日志数据到表

1.2:操作日志数据到文件

2:过滤器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Text;
using System.Diagnostics;
using QzjcService.Models.Dto.LogModels;
using QzjcService.Controllers;
using SqlSugar.IOC;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using QzjcService.Helper;
using Microsoft.AspNetCore.Mvc;
using QzjcService.Models; namespace QzjcService.Filters
{
public class ActionNewLogFilter : ActionFilterAttribute
{
private static Stopwatch _watting = new Stopwatch();
public static double? longtime = 0;
private ActionLogModel log = new ActionLogModel();
private readonly ILogger<ActionNewLogFilter> _logger; public ActionNewLogFilter(ILogger<ActionNewLogFilter> logger)
{
_logger = logger;
} public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
_watting.Start();
string controllerName = context.ActionDescriptor.RouteValues["controller"];
string actionName = context.ActionDescriptor.RouteValues["action"];
string method = context.HttpContext.Request.Method;//请求方式
string queryString = context.HttpContext.Request.QueryString.Value;//地址参数
string argments = JsonConvert.SerializeObject(context.ActionArguments);
string url = context.HttpContext.Request.Host + context.HttpContext.Request.Path;//接口地址
var logStr = string.Format("\r\n【接口地址】:{0} \r\n【请求方式】:{1} \r\n【地址参数】:{2} \r\n【Body参数】:{3}", new object[] { url, method, queryString, argments });
log.ControllerName = controllerName;
log.ActionName = actionName; //请求方式 0:get, 1:Post
log.Menthod = (method.Equals("get", StringComparison.InvariantCultureIgnoreCase) || method.Equals("httpget", StringComparison.InvariantCultureIgnoreCase)) ? 0 : 1;
log.CreateTime = DateTime.Now;
log.RequstParms = logStr;
var _context = context.HttpContext;
if (_context != null)
{
var tokenStr = context.HttpContext.Request.Headers[ConstData.Authorization].ToString();
log.userId = string.IsNullOrEmpty(tokenStr) ? 0 : TokenHelper.GetUserModel(context.HttpContext)?.UserId;
}
await base.OnActionExecutionAsync(context, next);
}
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
_watting.Stop();
longtime = 0;
if (context.Result is ObjectResult result)
{
if (result != null)
log.ResposeParam = JsonConvert.SerializeObject(result.Value);
}
longtime = _watting.Elapsed.TotalMilliseconds;
log.LongTimeMs = longtime.Value;
_watting.Reset();
log.RequstParms += "\r\n【响应参数】:" + log.ResposeParam + "\r\n============================================";
_logger.LogCritical(log.RequstParms);
// await DbScoped.Sugar.Insertable<ActionLogModel>(log).ExecuteCommandAsync();
await LogQueueHelper.EnQueueLogAsync(log);
await base.OnResultExecutionAsync(context, next);
} }
}
3:后台自带的定时器
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using QzjcService.Helper;
using QzjcService.Models.Dto.LogModels;
using SqlSugar.IOC;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace QzjcService.Services
{
public class LogTimeService : BackgroundService
{
private readonly ILogger<LogTimeService> _logger;
public LogTimeService(ILogger<LogTimeService> logger )
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Factory.StartNew(async () =>
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
var model = await LogQueueHelper.DeQueueLogAsync();
if (model != null)
{
Console.WriteLine($"===={DateTime.Now}=LogTimeService=DeQueueLog Success====");
await DbScoped.Sugar.Insertable<ActionLogModel>(model).ExecuteCommandAsync();
}
await Task.Delay(3000);
}
catch (Exception ex)
{
_logger.LogError($"====={DateTime.Now}===LogTimeService异常:=={ex.Message}==========");
continue;
}
}
}); }
}
}
4:Log记录Model
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace QzjcService.Models.Dto.LogModels
{
[Table("qzjc_action_loginfos")]
[SugarTable("qzjc_action_loginfos")]
public class ActionLogModel
{
/// <summary>
///
/// </summary>
[Column("id")]
[SugarColumn(ColumnName = "id")]
public int id { get; set; } /// <summary>
///
/// </summary>
[Column("controller_name")]
[SugarColumn(ColumnName = "controller_name")]
public string ControllerName { get; set; } /// <summary>
///
/// </summary>
[Column("action_name")]
[SugarColumn(ColumnName = "action_name")]
public string ActionName { get; set; } /// <summary>
///
/// </summary>
[Column("request_parms")]
[SugarColumn(ColumnName = "request_parms")]
public string RequstParms { get; set; } /// <summary>
///
/// </summary>
[Column("long_time")]
[SugarColumn(ColumnName = "long_time")]
public double LongTimeMs { get; set; } /// <summary>
///
/// </summary>
[Column("create_time")]
[SugarColumn(ColumnName = "create_time")]
public DateTime CreateTime { get; set; } /// <summary>
///
/// </summary>
[Column("create_userid")]
[SugarColumn(ColumnName = "create_userid")]
public int? userId { get; set; } [Column("menthod")]
[SugarColumn(ColumnName ="")]
public int? Menthod { get; set; } //[Column("state")]
//[SugarColumn(ColumnName = "state")]
//public int? State { get; set; } [Column("respose_parms")]
[SugarColumn(ColumnName = "respose_parms")]
public string ResposeParam { get; set; }
}
}
5:这里也贴出Serilog相关code
using System;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using Serilog;
using Serilog.Events; namespace QzjcService
{
public class Program
{
public static void Main(string[] args)
{
string dataTime = DateTime.Now.ToString("yyyy-MM-dd");//这里去掉更好,让其自增长
string fileStr = $"Logs/{dataTime}_logs.txt";
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Warning() //Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Async(c => c.File(fileStr, rollOnFileSizeLimit: true, fileSizeLimitBytes: 1024 * 1024 * 10, retainedFileCountLimit: 30))
.CreateLogger();
try
{
Log.Information("=========Starting web host==========");
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly!");
}
finally
{
Log.CloseAndFlush();
}
} public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, builder) =>
{
builder.ClearProviders();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(c => { c.Limits.MaxRequestBodySize = 1024 * 1024 * 300; });
webBuilder.UseUrls("http://*:4444");
webBuilder.UseStartup<Startup>();
})
.UseSerilog();
}
}
<PackageReference Include="Serilog.Extensions.Hosting" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.2.0" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
使用.NetCore自带的后台作业,出入队简单模拟生产者消费者处理请求响应的数据的更多相关文章
- Python推导式详解,带你写出比较精简酷炫的代码
Python推导式详解,带你写出比较精简酷炫的代码 前言 1.推导式分类与用法 1.1 列表推导 1.2 集合推导 1.3 字典推导 1.4 元组推导?不存在的 2.推导式的性能 2.1 列表推导式与 ...
- 【Javascript Demo】遮罩层和百度地图弹出层简单实现
其实想做的就是显示百度地图的弹出层,现在已经简单实现了.示例和代码如下,点击按钮可以看到效果: 1.示例: 2.代码: <!DOCTYPE html PUBLIC "-//W3C/ ...
- 【Javascript Demo】遮罩层和弹出层简单实现
最近纠结于遮罩层和弹出层的实现,终于搞定了个简单的版本.示例和代码如下,点击按钮可以看到效果: 1.示例: 2.代码: <!DOCTYPE html PUBLIC "-//W3C//D ...
- 在使用Ajax请求返回json数据的时候IE浏览器弹出下载保存对话框的解决方法
在使用Ajax请求返回json数据的时候IE浏览器弹出下载保存对话框的解决方法 最近在做一个小东西,使用kindeditor上传图片的时候,自己写了一个上传的方法,按照协议规则通过ajax返回json ...
- PDO 拿出來的 Float 數據跟数据库中的数据不匹配
数据库中的价格字段是 float 类型的,在 Laravel 中取出会出现这样的情况 数据库:71.9 -> 程序打印:72.0 数据库:75.2 -> 程序打印:75.3 在另外一个测试 ...
- 【452】pandas筛选出表中满足另一个表所有条件的数据
参考:pandas筛选出表中满足另一个表所有条件的数据 参考:pandas:匹配两个dataframe 使用 pd.merge 来实现 on 表示查询的 columns,如果都有 id,那么这是很好的 ...
- C语言:将带头节点的单向链表结点域中的数据从小到大排序。-求出单向链表结点(不包括头节点)数据域中的最大值。-将M*N的二维数组中的数据,按行依次放入一维数组,
//函数fun功能是将带头节点的单向链表结点域中的数据从小到大排序. //相当于数组的冒泡排序. #include <stdio.h> #include <stdlib.h> ...
- 终于等到你!MobileTest免费公测,华为带你走出安卓适配大坑
一.安卓适配之痛真的无解吗? Android平台的诞生对智能手机的普及功不可没,但设备繁多.品牌众多.版本各异,芯片.摄像头.分辨率不统一等等,这些都逐渐成为Android系统发展的障碍,碎片化严重不 ...
- 利用ASP.netCore自带DI(DependencyInjection)实现批量依赖注入
ASP.net Core自带DI(依赖注入),用法如下: services.AddScoped(typeof(IProductService), typeof(ProductService)); 如果 ...
随机推荐
- Java语言学习day37--8月12日
今日内容介绍1.List接口2.Set接口3.判断集合唯一性原理 ###01List接口的特点 A:List接口的特点: a:它是一个元素存取有序的集合. 例如,存元素的顺序是11.22.33.那么 ...
- 伪元素 Before & Aster
1. html 结构 <label class="is-required" for="name">姓名</label> <inpu ...
- Typora使用手册(基础)
Typora使用手册 第一步,你首先得拥有一个Typora,可通过(https://typoraio.cn/)该网址下载. 第二步,安装并打开. 第三步,让我们开始认识并设置自己的Typora吧~ 什 ...
- Java 线程池四种拒绝策略
jdk1.5版本新增了 JUC 并发包,其中一个包含线程池. 四种拒绝策略: 拒绝策略类型 说明 1 ThreadPoolExecutor.AbortPolicy 默认拒绝策略,拒绝任务并抛出任务 2 ...
- ABP应用开发(Step by Step)-下篇
测试 ProductAppService 类 启动模板附带测试基础架构,包括xUnit.Shouldly和NSubstitute库.它使用SQLite 内存数据库来模拟数据库,并为每个测试创建一个单独 ...
- stm32F103RCT6的DMA使用经历
DMA可以直接传输数据,减少了CPU的负担,是个很好的功能,但是用的时候难免会一头雾水.这次做个小小的串口收发程序就碰到了许多问题. 之前没有注意,选择了DMA的circular模式,然后奇怪的事 ...
- 团队Beta2
队名:观光队 链接 组长博客 作业博客 组员实践情况 王耀鑫 **过去两天完成了哪些任务 ** 文字/口头描述 学习 展示GitHub当日代码/文档签入记录 接下来的计划 完成短租车,页面美化 **还 ...
- 阿里新零售中的智能补货(I)— 库存模型
文章作者:阿里零售通算法团队 出品社区:DataFun 导读: 零售通作为阿里巴巴新零售的八路大军之一,肩负着"共建智能分销平台"和"让百万小店拥抱DT时代"的 ...
- 为 map 中不存在的 key 提供缺省值
需求 需要往一个复杂的 map 中写入数据,或为 map 中不存在 key 提供 default value java standard library Map<K, List<V> ...
- 【Unity Shader学习笔记】Unity基础纹理-法线贴图
1 高度纹理 使用一张纹理改变物体表面法线,为模型提供更多细节. 有两种主要方法: 1.高度映射:使用一张高度纹理(height map)来模拟表面位移(displacement).得到一个修改后的法 ...