2

使用.NetCore自带的后台作业,出入队简单模拟生产者消费者处理请求响应的数据 - 天天...

 1 year ago
source link: https://www.cnblogs.com/Fengge518/p/16420265.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用.NetCore自带的后台作业,出入队简单模拟生产者消费者处理请求响应的数据

环境:Core:3.1的项目

说明:由于该方案为个人测试项目,重启时队列中的部分数据很可能会丢失,

对数据有要求的该方案不适用,不能照搬需要持久化处理,

另外发布到Linux Docker中通常不会自动回收,但是发布到IIS中需要简单设置不回收即可!!! 如下截图:

在IIS中找到这个站点所用的程序池,点击 高级设置。。。 

1734768-20220628172822920-1767689744.png

回收——固定时间间隔       修改为 0

回收——虚拟/专用内存限制   修改为 0

进程模型——闲置超时       修改为 0

1:先来看效果

1.1:操作日志数据到表

1734768-20220628170221275-1891825838.png

 1.2:操作日志数据到文件

1734768-20220628172013734-400759085.png

 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" />


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK