Web APi之异常处理(Exception)以及日志记录(NLog)(十六)
前言
上一篇文章我们介绍了关于日志记录用的是Log4net,确实也很挺强大,但是别忘了我们.NET有专属于我们的日志框架,那就是NLog,相对于Log4net而言,NLog可以说也是一个很好的记录日志的框架,并且其中的异步日志等都有非常大的改善,本文借此用了最新的NLog来在Web APi中进行记录日志。
NLog
第一步则是下载我们需要的程序包,包括程序集以及配置文件

利用NLog记录日志同样可以实现如我们上篇文章利用Log4net来实现的那样,所以在这里就不多说,下面我们来讲另外一种方式,那就是利用.NET内置的跟踪级别类来进行记录日志。从而达到我们所需。
在NLog.config配置文件中,我们添加如下进行日志的记录【注意:只是简单的利用了NLog,它还是比较强大,更多的详细内容请到官网或通过其他途径进行学习】
<targets>
<target name="logfile" xsi:type="File" fileName="${basedir}/WebAPiNLog/${date:format=yyyyMMdd}.log" /> //在根目录下的WebAPiNlog文件下生成日志
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="logfile" />
</rules>
第二步
既然是利用.NET内置的跟踪级别类来实现,那么我们就需要实现其接口 ITraceWriter ,该接口需要实现如下方法
// 摘要:
// 当且仅当在给定 category 和 level 允许跟踪时,调用指定的 traceAction 以允许在新的 System.Web.Http.Tracing.TraceRecord
// 中设置值。
//
// 参数:
// request:
// 当前 System.Net.Http.HttpRequestMessage。它可以为 null,但这样做将阻止后续跟踪分析将跟踪与特定请求关联。
//
// category:
// 跟踪的逻辑类别。用户可以定义自己的跟踪。
//
// level:
// 写入此跟踪时所在的 System.Web.Http.Tracing.TraceLevel。
//
// traceAction:
// 启用了跟踪时要调用的操作。在此操作中,调用方应填充给定 System.Web.Http.Tracing.TraceRecord 的各个字段。
void Trace(HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction);
【注意】利用内置的跟踪级别则需要引用如下命名空间
using System.Web.Http.Tracing;
首先创建一个NLogger类并实现如上接口,当然我们也得创建NLog实例并利用其实例进行级别处理,如下:
private static readonly Logger NlogLogger = LogManager.GetCurrentClassLogger();
接着我们该如何做呢?我们需要利用 TraceLevel 跟踪级别,同时结合NLog得到相应的级别信息,可能创建对象实例的过程比较长,我们可以利用Lazy<>来实现延迟加载,代码如下:
private static readonly Lazy<Dictionary<TraceLevel, Action<string>>> LoggingMap = new Lazy<Dictionary<TraceLevel, Action<string>>>
(() => new Dictionary<TraceLevel, Action<string>>
{{ TraceLevel.Info, NlogLogger.Info },
{ TraceLevel.Debug, NlogLogger.Debug },
{ TraceLevel.Error, NlogLogger.Error },
{ TraceLevel.Fatal, NlogLogger.Fatal },
{ TraceLevel.Warn, NlogLogger.Warn }
});
然后,我们定义一个属性来返回其实例的值,如下
private Dictionary<TraceLevel, Action<string>> Logger
{
get { return LoggingMap.Value; }
}
紧接着我们就是实现上述ITraceWriter接口
public void Trace(System.Net.Http.HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction)
{
if (level != TraceLevel.Off) //如果没用禁用日志跟踪
{
if (traceAction != null && traceAction.Target != null)
{
category = category + Environment.NewLine + "Action Parameters : " + JsonConvert.SerializeObject(traceAction.Target);
}
var record = new TraceRecord(request, category, level);
if (traceAction != null) traceAction(record);
Log(record);
} }
我们记录请求的参数,URL,以及Token、返回的JSON等等,上述Log方法则如下
private void Log(TraceRecord record)
{
var message = new StringBuilder(); if (!string.IsNullOrWhiteSpace(record.Message))
message.Append("").Append(record.Message + Environment.NewLine); if (record.Request != null)
{
if (record.Request.Method != null)
message.Append("Method: " + record.Request.Method + Environment.NewLine); if (record.Request.RequestUri != null)
message.Append("").Append("URL: " + record.Request.RequestUri + Environment.NewLine); if (record.Request.Headers != null && record.Request.Headers.Contains("Token") && record.Request.Headers.GetValues("Token") != null && record.Request.Headers.GetValues("Token").FirstOrDefault() != null)
message.Append("").Append("Token: " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine);
} if (!string.IsNullOrWhiteSpace(record.Category))
message.Append("").Append(record.Category); if (!string.IsNullOrWhiteSpace(record.Operator))
message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation);
}
第三步
我们自定义日志特性取名为 NLogFilterAttribute ,我们在访问Action时来进行记载日志也就是需要继承于 ActionFilterAttribute ,简单来说代码如下:
public class NLogFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext filterContext)
{......}
}
那么问题来了,.NET默认确确实实是走得内置的跟踪级别,我们如何让其实现我们上述实现的接口的级别呢?
此时我们之前所学就派上了一点用场,我们将其服务容器的关于ITraceWriter接口实现进行替换我们自定义实现的接口即可,用如下一句即可
GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogHelper());
接下来就是从服务容器中获取我们自定义实现的跟踪级别
var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();
然后调用比如说隔离级别中的Info,获取其访问的控制器名、Action名称以及JSON等数据,如下:
trace.Info(filterContext.Request,
"Controller : " + filterContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine +
"Action : " + filterContext.ActionDescriptor.ActionName,
"JSON", filterContext.ActionArguments);
我们简单个给出所请求的控制器以及需要返回的数据,如下:
public class AboutController : ApiController
{
[POST("about")]
public string about()
{
var test = new
{
name = "xpy0928",
gender = "男",
age =
};
return Newtonsoft.Json.JsonConvert.SerializeObject(test);
}
}
接下来我们利用WebAPiTestOnHelpPage进行测试,看结果是否如我们所期望

结果如我们所期待的那样

但是我们的重点是是否生成了相应的日志,我们一起来看下:

到此,关于利用.NET内置的跟踪级别结合NLog来实现日志的记录也就告一段落,接下来我们来看看异常处理
Exception
既然异常处理,那么我们当然就得利用自定义异常特性实现 ExceptionFilterAttribute ,其基本实现如下:
public class CustomExceptionAttribute:ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{....}
}
关于其实现和上面大同小异,如下
GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogHelper());
var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();
trace.Error(actionExecutedContext.Request, "Controller : " + actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + actionExecutedContext.ActionContext.ActionDescriptor.ActionName, actionExecutedContext.Exception); var exceptionType = actionExecutedContext.Exception.GetType(); if (exceptionType == typeof(ValidationException))
{
var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent(actionExecutedContext.Exception.Message), ReasonPhrase = "ValidationException", };
throw new HttpResponseException(resp); }
else if (exceptionType == typeof(UnauthorizedAccessException))
{
throw new HttpResponseException(actionExecutedContext.Request.CreateResponse(HttpStatusCode.Unauthorized));
}
else
{
throw new HttpResponseException(actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError));
}
此时我们还需要在日志NLogger类中添加如下一句
//处理异常
if (record.Exception != null && !string.IsNullOrWhiteSpace(record.Exception.GetBaseException().Message))
{
var exceptionType = record.Exception.GetType();
message.Append(Environment.NewLine);
message.Append("").Append("Error: " + record.Exception.GetBaseException().Message + Environment.NewLine);
}
如此就基本实现了利用NLog记录异常,当然我们可以自定义个异常类来更好的管理异常例如,如下:
public class ApiExceptions:Exception
{ int ErrorCode { get; set; } string ErrorDescription { get; set; } HttpStatusCode HttpStatus { get; set; } }
总结
本节我们学习了利用NLog来实现记录异常通过集合内置的跟踪级别。NLog是属于.NET所以就单独拿来讲讲,其强大也是不可言喻的。
Web APi之异常处理(Exception)以及日志记录(NLog)(十六)的更多相关文章
- Exception Handling in ASP.NET Web API webapi异常处理
原文:http://www.asp.net/web-api/overview/error-handling/exception-handling This article describes erro ...
- Web API统一异常处理 【转载】
前面讲了webapi的安全验证和参数安全,不清楚的朋友,可以看看前面的文章,<Web API系列(二)接口安全和参数校验>,本文主要介绍Web API异常结果的处理.作为内部或者是对外提供 ...
- Web API删除JSON格式的文件记录
Insus.NET的系列Web Api学习文章,这篇算是计划中最后一篇了,删除JSON格式的文件记录.前一篇<Web Api其中的PUT功能演示>http://www.cnblogs.co ...
- ASP.NET Core 入门教程 10、ASP.NET Core 日志记录(NLog)入门
一.前言 1.本教程主要内容 ASP.NET Core + 内置日志组件记录控制台日志 ASP.NET Core + NLog 按天记录本地日志 ASP.NET Core + NLog 将日志按自定义 ...
- web API 的异常处理
实现自定义的异常处理类 --------------------------------------------------------------------- public class MyExc ...
- arcgis api 3.x for js 入门开发系列十六迁徙流动图
前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...
- Hadoop MapReduce编程 API入门系列之二次排序(十六)
不多说,直接上代码. -- ::, INFO [org.apache.hadoop.metrics.jvm.JvmMetrics] - Initializing JVM Metrics with pr ...
- JavaWeb学习记录(十六)——防止表单重复提交
产生随机字符串进行验证,如果产生的和Session存储的相同则可以提交,提交后删除session对应的属性值:否则表单提交不成功 一.产生随机字符串的工具类 package web10.util; i ...
- Linux 入门记录:十六、Linux 多命令协作:管道及重定向
一.多命令协作 在 Linux 系统当中,大多数命令都很简单,很少出现复杂功能的命令,每个命令往往只实现一个或多个很简单的功能.通过将不同功能的命令组合一起使用,可以实现某个复杂功能的. Linux ...
随机推荐
- 【Beta】Daily Scrum Meeting第一次
1.任务进度 学号 已完成 接下去要做 502 更换网络框架为okHttp 搭建好PHP单元测试环境,写出PHP测试的demo 509 PHP的login返回值:插入数据改为单行插入:系负责人更新单行 ...
- 字符串、数组方法实战--charAt(),split(),indexOf(),substring()
这篇随笔根据两个面试题来实战一下数组.字符串的一些方法. 题一:一个字符串中找出出现次数最多的字符次数 var str = 'fuuhuhuhufaihuhfnkjNKCNIO'; function ...
- webpack模块加载css文件及图片地址
webpack支持css文件加载并打包,只需安装相应加载器并在配置文件中配置 . 加载的css文件内容会与该模块里的js内容混合封装,这样做的好处是一个js文件包含了所有的css与js内容,有效减少了 ...
- USACO翻译:USACO 2013 NOV Silver三题
USACO 2013 NOV SILVER 一.题目概览 中文题目名称 未有的奶牛 拥挤的奶牛 弹簧牛 英文题目名称 nocow crowded pogocow 可执行文件名 nocow crowde ...
- 谢欣伦 - OpenDev原创例程 - 网络摄像机WebCamera
Win7没有预装摄像头软件,打开摄像头通常需要第三方软件来完成.第三方软件,好的要收费,免费的又没几款,其中功能完整的寥寥可数.正好我在做一个数字摄像头视频捕获的功能,经过两周的整理优化,我做了一个简 ...
- 谢欣伦 - OpenDev原创例程 - 串口助手Comm Assist
前一段时间,一位博友发邮件给我.他跟我讲说没太看懂<化繁为简系列原创教程 - 通信专题 - 串口类CxComm的使用>,请我做一个DEMO工程给他.我抽了一天时间编写并上传了一个DEMO工 ...
- while(cin.eof)出错 poj
zoj遇到c++如何判定输入流结尾的问题,一不小心就超时了 楼下的代码可以通过zoj #include<iostream> using namespace std; int main(){ ...
- Mvc form提交
在项目开发中,我们离不开表单提交,本篇主要记录mvc的Ajax.BeginForm提交方式. 需要用到的js @Url.Script("~/Content/Scripts/jquer ...
- 学习笔记:delphi多线程知识
最近一直在温习旧的知识,刚好学习了一下Java的线程安全方面的知识,今天想起之前一直做的Delphi开发,所以还是有必要温习一下,看看这些不同的编程语言有什么不同之处. Delphi的线程同步方法: ...
- CYQ.Data 批量添加数据性能测试(每秒千、万)
今天有网友火晋地同学进了CYQ.Data官方群了,他正在折腾了一个各大ORM性能测试的比较的软件,如下图 折腾的种类也不少: 感觉这软件折腾的不错~~~值的期待~~~ 另外,他指出CYQ.Data 在 ...