如何让 Web API 微信统一下单api回传格式以及例外处理

Web APi之异常处理(Exception)以及日志记录(NLog)(十六) - 推酷
Web APi之异常处理(Exception)以及日志记录(NLog)(十六)
上一篇文章我们介绍了关于日志记录用的是Log4net,确实也很挺强大,但是别忘了我们.NET有专属于我们的日志框架,那就是NLog,相对于Log4net而言,NLog可以说也是一个很好的记录日志的框架,并且其中的异步日志等都有非常大的改善,本文借此用了最新的NLog来在Web APi中进行记录日志。
第一步则是下载我们需要的程序包,包括程序集以及配置文件
利用NLog记录日志同样可以实现如我们上篇文章利用Log4net来实现的那样,所以在这里就不多说,下面我们来讲另外一种方式,那就是利用.NET内置的跟踪级别类来进行记录日志。从而达到我们所需。
在NLog.config配置文件中,我们添加如下进行日志的记录【注意:只是简单的利用了NLog,它还是比较强大,更多的详细内容请到官网或通过其他途径进行学习】
&target name=&logfile& xsi:type=&File& fileName=&${basedir}/WebAPiNLog/${date:format=yyyyMMdd}.log& /& //在根目录下的WebAPiNlog文件下生成日志
&/targets&
&logger name=&*& minlevel=&Trace& writeTo=&logfile& /&
既然是利用.NET内置的跟踪级别类来实现,那么我们就需要实现其接口 ITraceWriter ,该接口需要实现如下方法
当且仅当在给定 category 和 level 允许跟踪时,调用指定的 traceAction 以允许在新的 System.Web.Http.Tracing.TraceRecord
中设置值。
当前 System.Net.Http.HttpRequestMessage。它可以为 null,但这样做将阻止后续跟踪分析将跟踪与特定请求关联。
跟踪的逻辑类别。用户可以定义自己的跟踪。
写入此跟踪时所在的 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.T
首先创建一个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.Debug, NlogLogger.Debug },
{ TraceLevel.Error, NlogLogger.Error },
{ TraceLevel.Fatal, NlogLogger.Fatal },
{ TraceLevel.Warn, NlogLogger.Warn }
然后,我们定义一个属性来返回其实例的值,如下
private Dictionary&TraceLevel, Action&string&& Logger
get { return LoggingMap.V }
紧接着我们就是实现上述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);
我们自定义日志特性取名为 NLogFilerAttribute ,我们在访问Action时来进行记载日志也就是需要继承于& ActionFilterAttribute ,简单来说代码如下:
public class NLogFilerAttribute : 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等数据,如下:
(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 = &男&,
return Newtonsoft.Json.JsonConvert.SerializeObject(test);
接下来我们利用WebAPiTestOnHelpPage进行测试,看结果是否如我们所期望
结果如我们所期待的那样
但是我们的重点是是否生成了相应的日志,我们一起来看下:
到此,关于利用.NET内置的跟踪级别结合NLog来实现日志的记录也就告一段落,接下来我们来看看异常处理
既然异常处理,那么我们当然就得利用自定义异常特性实现 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));
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 { }
string ErrorDescription { }
HttpStatusCode HttpStatus { }
本节我们学习了利用NLog来实现记录异常通过集合内置的跟踪级别。NLog是属于.NET所以就单独拿来讲讲,其强大也是不可言喻的。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看&
本文主要来讲解Asp.Net Web API中错误和异常的处理,包括以下几点:
  1.HttpResponseException&&HTTP响应异常
  2.Exception Filters&&异常过滤器
  3.Registering Exception Filters&&注册异常过滤器
  4.HttpError&&HTTP错误
HttpResponseException&&HTTP响应异常
  &如果一个Web API 控制器抛出一个未捕获的异常,会发生什么?在默认情况下,大多数异常都被转换为一个带有状态码500的内部服务器错误的HTTP响应。
这个HTTPResponseException类型是一个特殊的类型。这种异常会返回你在异常构造器中指定的任何HTTP状态码。例如,在以下方法中,如果这个id参数无效,那么会返回&404&&未找到&。
public Product GetProduct(int id)
Product item = repository.Get(id);
if (item == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
为了对响应进行更多的控制,你也可以构造整个响应消息,并用HTTPResponseException来包含它:
public Product GetProduct(int id)
Product item = repository.Get(id);
if (item == null)
var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
Content = new StringContent(string.Format("No product with ID = {0}", id)),
ReasonPhrase = "Product ID Not Found"
throw new HttpResponseException(resp);
Exception Filters&&异常过滤器
&  通过编写一个异常过滤器,你可以定制Web API如何处理异常。当一个控制器抛出一个未处理的异常,且这个异常不是一个HttpResponseException异常时,一个异常过滤器会被执行。HttpResponseException类型一个特殊的情况,因为它是专门设计用来返回一个HTTP响应的。
  异常过滤器实现System.Web.Http.Filters.IExceptionFilter接口。编写异常过滤器最简单的方式是通过System.Web.Http.Filters.ExceptionFilterAttribute类进行派生,并重写其OnException方法。
ASP.NET Web API中的异常过滤器与Asp.Net MVC中的是极为类似的。然后,他们被声明在不同的命名空间中,且功能也是独立的。特别强调一下,Asp.Net MVC中使用的HandleErrorAttribute类不会处理Web API控制器中抛出的异常。
&以下是将NotImplementedException异常转换成HTTP状态码&501 & 未实现&的一个过滤器:
using System.N
using System.Net.H
using System.Web.Http.F
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
public override void OnException(HttpActionExecutedContext context)
if (context.Exception is NotImplementedException)
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
HttpActionExecutedContext对象的Response属性含有将发送给客户端的HTTP响应消息。
Registering Exception Filters&&注册异常过滤器
&以下是注册Web API异常过滤器的几种方式:
通过动作进行注册
通过控制器进行注册
要把过滤应用于特定的动作,在动作上添加该过滤器的注解属性:
public class ProductsController : ApiController
[NotImplExceptionFilter]
public Contact GetContact(int id)
throw new NotImplementedException("This method is not implemented");
要把过滤器运用于一个控制器的所有动作,在控制器上添加该过滤器的注解属性:
[NotImplExceptionFilter]
public class ProductsController : ApiController
要全局性地把过滤器运用于所有Web API控制器,将该过滤器的一个实例添加到GlobalConfiguration.Configuration.Filters集合。这个集合中的异常过滤器会运用于任何Web API控制器动作。
GlobalConfiguration.Configuration.Filters.Add(
new ProductStore.NotImplExceptionFilterAttribute());
如果你用的是&ASP.NET MVC 4 Web应用程序&项目模板创建的项目,要把你的Web API配置代码被放在WebApiConfig类中,它位于App_Start文件夹:
public static class WebApiConfig
public static void Register(HttpConfiguration config)
config.Filters.Add(new ProductStore.NotImplExceptionFilterAttribute());
// Other configuration code(其它配置代码)...
HttpError&&HTTP错误
&HttpError对象为在响应正文中返回错误消息提供了相应的方式。以下示例演示了如何用HttpError在响应体中返回HTTP状态码&404 & 未找到&:
public HttpResponseMessage GetProduct(int id)
Product item = repository.Get(id);
if (item == null)
var message = string.Format("Product with id = {0} not found", id);
HttpError err = new HttpError(message);
return Request.CreateResponse(HttpStatusCode.NotFound, err);
return Request.CreateResponse(HttpStatusCode.OK, item);
在这个例子中,如果该方法成功,它会在HTTP响应中返回产品。但如果所请求的产品未找到,则HTTP响应会在请求体中包含一个HttpError。该响应看上去大致像这样:
HTTP/1.1 404 Not Found
Content-Type: application/ charset=utf-8
Date: Thu, 09 Aug 2012 23:27:18 GMT
Content-Length: 51
"Message": "Product with id = 12 not found"
注意,在这个例子中,HttpError会被序列化成JSON。使用HttpError的一个好处是,与其它强类型模型一样,会进行同样的&content-negotiation&(暂未实现)和序列化过程。
直接替代创建HttpError对象的一种办法是,你可以使用CreateErrorResponse方法:
public HttpResponseMessage GetProduct(int id)
Product item = repository.Get(id);
if (item == null)
var message = string.Format("Product with id = {0} not found", id);
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
return Request.CreateResponse(HttpStatusCode.OK, item);
CreateErrorResponse在System.Net.Http.HttpRequestMessageExtensions类中被定义为一个扩展方法。本质上,CreateErrorResponse会创建一个HttpError实例,然后创建一个包含该HttpError的HttpResponseMessage。
Adding Custom Key-Values to HttpError把自定义的键值添加到HTTPError
HttpError类实际上是一个&键-值&集合(它派生于Dictionary&string, object&),因此你可以添加自己的&键-值&对:
public HttpResponseMessage GetProduct(int id)
Product item = repository.Get(id);
if (item == null)
var message = string.Format("Product with id = {0} not found", id);
var err = new HttpError(message);
err["error_sub_code"] = 42;
return Request.CreateErrorResponse(HttpStatusCode.NotFound, err);
return Request.CreateResponse(HttpStatusCode.OK, item);
Using HttpError with HttpResponseException以HttpResponseException的方式来使用HttpError
&前面的例子是从控制器动作返回一个HttpResponseMessage消息,但你也可以使用HttpResponseException来返回一个HttpError。这让你能够在正常成功情况下返回强类型模型,而在有错误时,仍返回HttpError。
public Product GetProduct(int id)
Product item = repository.Get(id);
if (item == null)
var message = string.Format("Product with id = {0} not found", id);
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
&  感觉比MVC中的异常处理更为出色,不知道新版本的MVC中的异常处理机制如何。下一篇文章将来讲解Web API2中新增加的一个亮点机制&&&&属性路由,貌似很牛逼的样子。
阅读(...) 评论()c#开发(20)
构建高性能应用(1)
最近做一个pos系统需要定时向服务器传送交易数据,大家都知道传输数据需要联网状态,如果不判断当前设备是否处理联网状态而直接传送数据,有可能会造成线程阻塞等这样那样的问题。所以我写了一个判断设备是否处于联网状态的方法。
&/// &summary&
& & & /// 测试系统是否联网
& & & /// &/summary&
& & & /// &returns&&/returns&
& & & & public static bool testIsHaveInternet()
& & & & & & HttpClient client = new HttpClient();
& & & & & & client.BaseAddress = new Uri(&&);
& & & & & & // Add an Accept header for JSON format.
& & & & & & // 为JSON格式添加一个Accept报头
& & & & & & client.DefaultRequestHeaders.Accept.Add(
& & & & & & & & new MediaTypeWithQualityHeaderValue(&application/json&));
& & & & & & HttpResponseMessage response = client.GetAsync(&api/products&).R &// Blocking call(阻塞调用)!&
& & & & & & if (response.IsSuccessStatusCode)
& & & & & & {
& & & & & & & &
& & & & & & }
& & & & & & else
& & & & & & {
& & & & & & & &
& & & & & & }
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:25565次
排名:千里之外
原创:38篇
评论:18条
(2)(1)(2)(3)(1)(2)(2)(8)(2)(2)(11)(8)(1)}

我要回帖

更多关于 统一api网关 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信