ASP.NET Core MVC之Serilog日志处理,你了解多少?
前言
本节我们来看看ASP.NET Core MVC中比较常用的功能,对于导入和导出目前仍在探索中,项目需要自定义列合并,所以事先探索了如何在ASP.NET Core MVC进行导入、导出,更高级的内容还需等我学习再给出。
EntityFramework Core
在学习ASP.NET Core MVC之前我们来看看在EF Core中如何更新对象指定属性,这个问题之前我们已经探讨过,但是还是存在一点问题,请往下看。
public void Update(T entity, params Expression<Func<T, object>>[] properties)
{
_context.Entry(entity).State = EntityState.Unchanged;
foreach (var property in properties)
{
var propertyName = ExpressionHelper.GetExpressionText(property);
_context.Entry(entity).Property(propertyName).IsModified = true;
}
}
上述方法可以用来更新对象指定属性,使用lambda来指定需要更新的属性,如下:
[HttpGet("[action]")]
public IActionResult Index()
{
var blog = new Blog() { Id = , Name = "Jeffcky1" };
_blogRepository.Update(blog, d => d.Name);
_blogRepository.SaveChanges();
}
但是当更新数值类型时会解析不到该属性,如下:
var blog = new Blog() { Id = , Count = };
_blogRepository.Update(blog, d => d.Count);
_blogRepository.SaveChanges();
此时得到该属性名称为空字符串

lambda为何解析不到呢?原来它进行了Convert如下:

既然是将其转换成了Convert,那么在表达式树中应该用其节点类型,如下:

此时我们需要判断其节点类型是否已经经过Convert即可,最终代码如下:
public void Update(T entity, params Expression<Func<T, object>>[] properties)
{ EntityEntry<T> entry = _context.Entry(entity);
entry.State = EntityState.Unchanged;
foreach (var property in properties)
{
string propertyName = "";
Expression bodyExpression = property.Body;
if (bodyExpression.NodeType == ExpressionType.Convert && bodyExpression is UnaryExpression)
{
Expression operand = ((UnaryExpression)property.Body).Operand;
propertyName = ((MemberExpression)operand).Member.Name;
}
else
{
propertyName = ExpressionHelper.GetExpressionText(property);
}
entry.Property(propertyName).IsModified = true;
}
}
此时将能正确解析到数值类型名称,如下:

为何要封装这一层,只是不想首先查询出对象然后再来进行更新属性,其两步操作合并为一步岂不爽哉。当然我们也可以不通过lambda来实现,直接给出属性集合,然后遍历即可,大概如下:
public void Update(T entity, params object[] properties)
{
_context.ChangeTracker.TrackGraph(entity, e =>
{
e.Entry.State = EntityState.Unchanged;
if ((e.Entry.Entity as T) != null)
{
foreach (var p in properties)
{
_context.Entry(e.Entry.Entity as T).Property(p.ToString()).IsModified = true;
} }
});
}
Serilog日志输出
目前比较流行的日志框架则是Log4net、NLog,之前也一直用的Log4net,但是在.net core中已经内置了日志框架Serilog,在github上也已加星不少,想必比较强大,既然这样为何不使用内置的呢,免去再用其他日志框架还要配置的麻烦。

创建默认项目在Startup中已经注入日志,如下:
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
当利用dotnet.exe调试时在控制台会显示调试各种信息,要是直接运行那该如何呢?在web中的配置文件web.config中,如下:
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
</system.webServer>
我们需要设置 stdoutLogEnabled="true" 来启动调试,此时运行项目你会发现屁都没有,此时我们查看windows日志发现根本无法创建文件夹,想必是没有权限的缘故。

此时我们需要手动创建logs文件夹,最终运行程序则会自动将所有信息写入到日志文件中,如下:

是不是这样就完了呢,这样设置则会将所有信息都会写入日志那样岂不是额外做些无用功,看看如下生成的日志。

光说不练假把式,来,我们来实现一个,让你见识见识Serilog的强大。先定义一个自定义输出格式的Option并创建输出日志文件夹。
public class JeffckyLogOptions
{
public string LogPath { get; set; } = @"C:\Jeffcky_StudyEFCore\logs"; public string PathFormat { get; set; } public static void EnsurePreConditions(JeffckyLogOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
} if (string.IsNullOrWhiteSpace(options.LogPath))
{
throw new ArgumentException("系统日志文件存储路径未配置", nameof(options.LogPath));
} if (string.IsNullOrWhiteSpace(options.PathFormat))
{
throw new ArgumentException("系统日志文件名称未配置", nameof(options.PathFormat));
} if (!Directory.Exists(options.LogPath))
{
Directory.CreateDirectory(options.LogPath);
}
}
}
内置实现日志的接口.net core已经给出,所以我们需要获取内置日志接口服务并实现自定义扩展方法。
app.ApplicationServices.GetService(typeof(ILoggerFactory));
此时上述app来源于 IApplicationBuilder 此时我们则只需要实现该接口的自定义扩展方法。我们开始下载Serilog程序包

此时我们需要对日志通过 LoggerConfiguration 类进行初始化配置。

接下来则是将日志写到文件中我们可以自定义格式,此时再下载如下程序包。

里面有个 RollingFile 方法来自定输出日志模板,自此我们就有了如下代码:
var serilog = new LoggerConfiguration()
.MinimumLevel.Debug()
.Enrich.FromLogContext()
.WriteTo.RollingFile(Path.Combine(options.LogPath, options.PathFormat),
outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {Message}{NewLine}{Exception}");
我们获取.net core内置的日志接口服务。
ILoggerFactory loggerFactory = (ILoggerFactory)app.ApplicationServices.GetService(typeof(ILoggerFactory));
同时设置我们输出日志的路径选项。
JeffckyLogOptions.EnsurePreConditions(options);
接下来将Serilog创建的日志添加到内置日志服务中,如下:
loggerFactory.AddSerilog(serilog.CreateLogger());
当然上述AddSerilog方法时扩展方法,此时我们仍需要添加如下扩展程序包:

最后还差一步则是日志的生命周期,灰常重要,为什么说灰常重要,我们要确保当程序关闭时或者系统出问题时所有在内存缓冲区的日志都将输送到日志文件夹中,如下:
// Ensure any buffered events are sent at shutdown
IApplicationLifetime appLifetime = (IApplicationLifetime)app.ApplicationServices.GetService(typeof(IApplicationLifetime));
if (appLifetime != null)
{
appLifetime.ApplicationStopped.Register(Log.CloseAndFlush);
}
一气呵成,最终我们在Startup的如下方法中进行调用即可:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{...}
利用Serilog添加自定日志格式输出,进行如下调用:
app.UseJeffckySelfDefineLog(new JeffckyLogOptions()
{
LogPath = Configuration[nameof(JeffckyLogOptions.LogPath)],
PathFormat = "Jeffcky_StudyEFCore_{Date}.log"
});
当然还有其他强大功能,比如Serilog中可以获取到上下文,这样的话我们就可以过滤对于那个应用程序使用对应的日志输出级别以及其他,如下:
serilog = serilog.Filter.ByIncludingOnly((e) =>
{
var context = e.Properties["SourceContext"].ToString(); return (context.StartsWith("\"Your Applicion Name") ||
e.Level == LogEventLevel.Warning ||
e.Level == LogEventLevel.Error ||
e.Level == LogEventLevel.Fatal);
});
说一千到一万,出现结果才是真理,我们一起来看看。

看看日志输出信息,你会看到干净的日志输出。

总结
本节我们详细讲解了.net core中新生代日志框架-Serilog,别抱着Log4net不放了,Serilog你值得拥有,跟着老大一直学习中,涨涨见识!因为项目中会用到批量导入和导出,所以在研究导出、导入,下节可能会讲到导入、导出在ASP.NET Core MVC中,也有可能会讲SQL Server中的最后几节关于死锁的内容,不管怎样都是在积累知识,你说呢,敬请期待!
ASP.NET Core MVC之Serilog日志处理,你了解多少?的更多相关文章
- asp.net core MVC 全局过滤器之ExceptionFilter异常过滤器(一)
本系类将会讲解asp.net core MVC中的内置全局过滤器的使用,将分为以下章节 asp.net core MVC 过滤器之ExceptionFilter异常过滤器(一) asp.net cor ...
- asp.net core MVC 过滤器之ActionFilter过滤器(二)
本系类将会讲解asp.net core MVC中的内置全局过滤器的使用,将分为以下章节 asp.net core MVC 过滤器之ExceptionFilter过滤器(一) asp.net core ...
- ASP.NET Core MVC+EF Core从开发到部署
笔记本电脑装了双系统(Windows 10和Ubuntu16.04)快半年了,平时有时间就喜欢切换到Ubuntu系统下耍耍Linux,熟悉熟悉Linux命令.Shell脚本以及Linux下的各种应用的 ...
- Asp.Net Core MVC框架内置过滤器
第一部分.MVC框架内置过滤器 下图展示了Asp.Net Core MVC框架默认实现的过滤器的执行顺序: Authorization Filters:身份验证过滤器,处在整个过滤器通道的最顶层.对应 ...
- ASP.NET Core MVC内置服务的使用
ASP.NET Core中的依赖注入可以说是无处不在,其通过创建一个ServiceCollection对象并将服务注册信息以ServiceDescriptor对象的形式添加在其中,其次针对Servic ...
- ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 02. Web Host 的默认配置
视频地址: https://www.bilibili.com/video/av38392956/?p=2 语雀 https://www.yuque.com/yuejiangliu/dotnet/ixt ...
- 从零开始实现ASP.NET Core MVC的插件式开发(六) - 如何加载插件引用
标题:从零开始实现ASP.NET Core MVC的插件式开发(六) - 如何加载插件引用. 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/1171 ...
- asp.net core MVC 过滤器之ExceptionFilter过滤器(一)
简介 异常过滤器,顾名思义,就是当程序发生异常时所使用的过滤器.用于在系统出现未捕获异常时的处理. 实现一个自定义异常过滤器 自定义一个异常过滤器需要实现IExceptionFilter接口 publ ...
- 如何在 ASP.Net Core 中使用 Serilog
记录日志的一个作用就是方便对应用程序进行跟踪和排错调查,在实际应用上都是引入 日志框架,但如果你的 日志文件 包含非结构化的数据,那么查询起来将是一个噩梦,所以需要在记录日志的时候采用结构化方式. 将 ...
随机推荐
- PHP下的命令行执行
PHP 的命令行模式 以下是 PHP 二进制文件(即 php.exe 程序)提供的命令行模式的选项参数,您随时可以通过 PHP -h 命令来查询这些参数. Usage: php [options] [ ...
- ecshop中ajax的调用原理 1
ecshop中ajax的调用原理 1:首先ecshop是如何定义ajax对象的. ecshop中的ajax对象是在js/transport.js文件中定义的.里面是ajax对象文件.声明了一个va ...
- java系列--HTTP协议
一.HTTP请求信息 请求行 请求头 空行 消息体 1.防盗链: 枚举类型: 二.中文乱码问题 1.Get提交 String username = request.getParameter(" ...
- 让VLC也拥有斷點播放功能
如何让VLC也拥有记忆功能,记住上次播放位置.以下都是在Windows系统下操作,其他 方法/步骤 下载 libsrpos_plugin-0.5.win 插件 https://sourceforge. ...
- windows apache 开启 GZIP
从服务端优化来说,通过对服务端做压缩配置可以大大减小文本文件的体积,从而使加载文本的速度成倍的加快.目前比较通用的压缩方法是启用gzip压缩.它 会把浏览器请求的页面,以及页面中引用的静态资源以压缩包 ...
- HTML 相同name 传递一个数组
今天发现一个很厉害的东西 在input表单中,name名称可以是一个,后面[],里面跟名称,和数组一样,传递到PHP中也是一个数组 <html> <body> <form ...
- TCP实现P2P通信
Internet的迅速发展以及IPv4 地址数量的限制使得网络地址翻译(NAT,Network Address Trans2lation)设备得到广泛应用.NAT设备允许处于同一NAT后的多台主机共享 ...
- SQL 日期筛选的两种方式
主要解决的是后一天的问题~容易漏掉最后一天~第一种方法,拼接String,第二种方法直接在最后一天加一天 第一: <if test="beginDate != null and beg ...
- MySQL timestamp NOT NULL插入NULL的问题
explicit_defaults_for_timestamp MySQL 5.6版本引入 explicit_defaults_for_timestamp 来控制对timestamp NULL值的处理 ...
- WMWARE下/sbin/scsi_id 返回值为空
[root@HE1 ~]# /sbin/scsi_id -g -u /dev/sdb 第一种是从VMWARE层面去解决,用文本编辑器修改vmx文件,在vmx文件中任意位置(通常在最后)添加如下行: d ...