• 使用.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:贴上系统自带的队列Queue

    复制代码
    using QzjcService.Models.Dto.LogModels;
    
    using System.Collections;
    using System.Threading.Channels;
    using System.Threading.Tasks;
    namespace QzjcService.Helper
    {
        public static class LogQueueHelper
        {
            public static Queue queue;
            private static readonly object Lock = new object();
            static LogQueueHelper()
            {
                queue = new Queue();
            }
            /// <summary>
            /// 
            /// </summary>
            /// <returns></returns>
            private static async Task<Queue> GetQueueAsync()
            {
                if (queue == null)
                {
                    lock (Lock)
                    {
                        if (queue == null)
                            queue = new Queue();
                    }
                }
                await Task.CompletedTask;
                return queue;
            }
    
            public static async Task<bool> EnQueueLogAsync(ActionLogModel model)
            {
                try
                {
                    queue = await GetQueueAsync();
                    queue.Enqueue(model);
                    return true;
                }
                catch (System.Exception)
                {
                    return false;
                }
            }
            public static async Task<ActionLogModel> DeQueueLogAsync()
            {
                try
                {
                    queue = await GetQueueAsync();
                    object obj = queue.Dequeue();
                    if (obj != null)
                    {
                        ActionLogModel model = obj as ActionLogModel;
                        return model ?? null;
                    }
                    return null;
                }
                catch (System.Exception)
                {
                    return null;
                }
            }
        }
    }
    复制代码

    6:这里也贴出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" />

    复制代码
  • 相关阅读:
    VSCode python extension loading 终极解决方案
    R-CNN(Regions with CNN features)
    linux之应用编程回顾总结
    读取jsonArray文件并转换为java对象工具类
    学习经验分享之十二:如何撰写论文
    力扣每日一题:1822:数组元素积的符号【模拟思维题】
    电子行业ERP解决方案
    力扣(leetcode)刷题分享,简单题(第1期)
    [NOIP2014 提高组] 生活大爆炸版石头剪刀布
    0049__Linux下文件关联的实现原理
  • 原文地址:https://www.cnblogs.com/Fengge518/p/16420265.html