.NET Core中使用NLog之封装、过滤器、注入全局使用

上篇咋们聊到NLog在Core中比较基础的使用,这篇接着上篇,对NLog做下封装和过滤器集成,然后全局使用

说道这里咋们想说说过滤器Filter,Filter其实是延续ASP.NET MVC的产物,同样保留了五种的Filter,分别是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。

本篇咋们就用NLog日志记录结合Filter中的Exception Filter异常日志全局过滤器,记录全局异常日志方便咋们排错,进入主题:

1、首先咋们创建个单独的项目,命名为Nlog.Framework,然后在类库中添加一个Log文件夹,把所有Log相关的文件都放到该文件夹下,添加后的项目结构如下图所示:

2、在Log文件下创建个LogMessage类,里面是要记录的一些信息属性字段,代码如下:

using System;
using System.Collections.Generic;
using System.Text;

namespace Nlog.Framework.Log
{
    /// <summary>
    /// 日志消息
    /// </summary>
    public class LogMessage
    {
        /// <summary>
        /// IP
        /// </summary>
        public string IpAddress { get; set; }

        /// <summary>
        /// 操作人
        /// </summary>
        public string OperationName { get; set; }

        /// <summary>
        /// 操作时间
        /// </summary>
        public DateTime OperationTime { get; set; }

        /// <summary>
        /// 日志信息
        /// </summary>
        public string LogInfo { get; set; }

        /// <summary>
        /// 跟踪信息
        /// </summary>
        public string StackTrace { get; set; }
    }
}
View Code

3、在Log文件下创建个格式化LogFormat类,用来格式化日志输出内容(日志看起来没那么凌乱),代码如下:

using System;
using System.Collections.Generic;
using System.Text;

namespace Nlog.Framework.Log
{
    public class LogFormat
    {
        public static string ErrorFormat(LogMessage logMessage)
        {
            StringBuilder strInfo = new StringBuilder();
            strInfo.Append("
");
            strInfo.Append("1. 操作时间: " + logMessage.OperationTime + " 
");
            strInfo.Append("2. 操作人: " + logMessage.OperationName + " 
");
            strInfo.Append("3. Ip  : " + logMessage.IpAddress + "
");
            strInfo.Append("4. 错误内容: " + logMessage.LogInfo + "
");
            strInfo.Append("5. 跟踪: " + logMessage.StackTrace + "
");
            strInfo.Append("----------------------------------------------------------------END---------------------------------------------------------------
");
            return strInfo.ToString();
        }
    }
}
View Code

4、在Log文件下定义一个接口,代码如下:

using System;
using System.Collections.Generic;
using System.Text;

namespace Nlog.Framework.Log
{
    public interface INLogHelper
    {
        void LogError(Exception ex);
    }
}
View Code

5、在Log文件下定义接口的实现类,代码如下:

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;

namespace Nlog.Framework.Log
{
    public class NLogHelper : INLogHelper
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ILogger<NLogHelper> _logger;
        public NLogHelper(IHttpContextAccessor httpContextAccessor, ILogger<NLogHelper> logger)
        {
            _httpContextAccessor = httpContextAccessor;
            _logger = logger;
        }

        public void LogError(Exception ex)
        {
            LogMessage logMessage = new LogMessage();
            logMessage.IpAddress = _httpContextAccessor.HttpContext.Request.Host.Host;
            if (ex.InnerException != null)
                logMessage.LogInfo = ex.InnerException.Message;
            else
                logMessage.LogInfo = ex.Message;
            logMessage.StackTrace = ex.StackTrace;
            logMessage.OperationTime = DateTime.Now;
            logMessage.OperationName = "administator";
            _logger.LogError(LogFormat.ErrorFormat(logMessage));

        }
    }
}
View Code

6、添加个Filter文件夹,在当前文件夹下创建个全局异常过滤器,代码如下:

using Microsoft.AspNetCore.Mvc.Filters;
using Nlog.Framework.Log;
using System;
using System.Threading.Tasks;

namespace FristCoreProgram.Filter
{
    public class CustomerGlobalExceptionFilterAsync : ActionFilterAttribute, IAsyncExceptionFilter
    {
        private readonly INLogHelper _logHelper;
        public CustomerGlobalExceptionFilterAsync(INLogHelper logHelper)
        {
            _logHelper = logHelper;
        }


        /// <summary>
        /// 重新OnExceptionAsync方法
        /// </summary>
        /// <param name="context">异常信息</param>
        /// <returns></returns>
        public Task OnExceptionAsync(ExceptionContext context)
        {
            // 如果异常没有被处理,则进行处理
            if (!context.ExceptionHandled)
            {
                // 记录错误信息
                _logHelper.LogError(context.Exception);
                // 设置为true,表示异常已经被处理了,其它捕获异常的地方就不会再处理了
                context.ExceptionHandled = true;
            }
            return Task.CompletedTask;
        }
    }
}
View Code

7、修改Program类文件,代码如下:

public static void Main(string[] args)
        {
            //设置读取指定位置的nlog.config文件
            //NLogBuilder.ConfigureNLog("XmlConfig/nlog.config");
            //CreateWebHostBuilder(args).Build().Run();


            //读取指定位置的NLog配置文件
            var logger = NLogBuilder.ConfigureNLog("XmlConfig/nlog.config").GetCurrentClassLogger();
            try
            {
                logger.Info("Init Main...");
                CreateWebHostBuilder(args).Build().Run();
            }
            catch (System.Exception ex)
            {
                logger.Error(ex, "Stopped program because of exception");
            }
            finally
            {
                LogManager.Shutdown();
            }
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                //配置使用Nlog
                .UseNLog();
View Code

8、在Startup类里面ConfigureServices注入全局异常过滤器,,代码如下:

public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc(options => {
                #region NLog过滤器注册
                options.Filters.Add(typeof(CustomerGlobalExceptionFilterAsync));
                #endregion
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

          
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton<INLogHelper, NLogHelper>();

            //services.AddControllers();

        }
View Code

PS:需要注意的是,由于Core的版本不同,Startup注入过滤器时方式有所不同

本例是core2.2版本注入的方式是:

    options.Filters.Add(typeof(CustomerGlobalExceptionFilterAsync));

而core3.1版本注入的方式是:

    services.AddControllers(options => options.Filters.Add(typeof(CustomerGlobalExceptionFilterAsync)));

9、最后再controller模拟个异常测试过滤器,代码如下:

最最最后,访问模拟异常的Action,查看日志文件,如下:

 以上完成,这里只是封装了Error,如果是其他级别的日志,可以自己封装,然后注入到Startup类中!

原文地址:https://www.cnblogs.com/become/p/15065997.html