一、WebAPI自定义过滤器的使用
1、注册过滤器
using System.Web.Http; using KYINT.WebAPIService.Handler; namespace KYINT.WebAPIService { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "ActionApi", routeTemplate: "{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); //移除XML格式,采用Json进行数据交互 config.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); //处理DateTime类型序列化后含有T的问题 config.Formatters.JsonFormatter.SerializerSettings.Converters.Insert(0, new JsonDateTimeConverter()); //添加全局异常处理器 config.Filters.Add(new KYExceptionFilter()); //添加全局认证过滤器 config.Filters.Add(new KYAuthenticationFilter()); //添加全局统计过滤器 config.Filters.Add(new StatisticsFilter()); } } }
2、全局认证过滤器
/// <summary> /// 认证过滤器,验证是否含有UUID标头 /// </summary> public class KYAuthenticationFilter : Attribute, IAuthenticationFilter { public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) { if (KYAuthenticationFilter.SkipAuthentication(context)) { return ; } IPrincipal principal = await this.AuthenticateAsync(context.Request); if (principal == null) { context.ErrorResult = new AuthenticationFailureResult("未授权请求", context.Request); } else { context.Principal = principal; } }
/// <summary> /// 从授权表头中取出授权值并验证,验证通过构建正确的Principal对象 /// </summary> /// <param name="request"></param> /// <returns></returns> private Task<IPrincipal> AuthenticateAsync(HttpRequestMessage request) { return Task.Run<IPrincipal>(() => { string UUID = request.GetHeader("UUID"); if (string.IsNullOrWhiteSpace(UUID)) { return null; } User user = TB_NUsersBLL.GetUser(UUID); if (user == null) { return null; } request.Properties.Add("UUID", user); IEnumerable<Claim> claims = new List<Claim>() { new Claim(ClaimTypes.Sid, UUID), new Claim(ClaimTypes.Name, user.UserName), new Claim(ClaimTypes.MobilePhone, user.TelePhone) }; return new ClaimsPrincipal(new ClaimsIdentity(claims)); }); } /// <summary> /// 检查控制器或方法是否启用NoAuthenticationAttribute,如果启用了,则跳过认证 /// </summary> /// <param name="context"></param> /// <returns></returns> private static bool SkipAuthentication(HttpAuthenticationContext context) { return context.ActionContext.ActionDescriptor.GetCustomAttributes<NoAuthenticationAttribute>().Any<NoAuthenticationAttribute>() || context.ActionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<NoAuthenticationAttribute>().Any<NoAuthenticationAttribute>(); } }
2.1、不需鉴权过滤器
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public sealed class NoAuthenticationAttribute : Attribute { }
3、全局统计过滤器
/// <summary> /// 全局统计过滤器 /// </summary> public class StatisticsFilter : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { base.OnActionExecuting(actionContext); //以下为业务处理 string methodName = actionContext.Request.RequestUri.AbsolutePath; //异步调用 Task.Factory.StartNew((obj) => TA_InteriorAppModuleInfoBLL.AddModuleInfo((string)obj), methodName); } }
4、全局异常过滤器
/// <summary> /// 全局异常过滤器 /// </summary> public class KYExceptionFilter : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext actionExecutedContext) { #region 标准做法 //var exception = actionExecutedContext.Exception; //if (exception is BusinessException) //业务异常,一般不需记录日志,直接反馈错误信息至前端 //{ // actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse((HttpStatusCode)exception.HResult, new HttpError(exception.Message)); //} //else //未处理异常如数据库访问出错、代码层面异常等,返回错误信息并记录日志 //{ // actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, new HttpError(exception.Message)); // //LogHelper.Error(typeof(KYExceptionFilter), exception); // LogHelper.Error(actionExecutedContext.Request.RequestUri.AbsolutePath, exception); //} #endregion #region 变异做法(受限于现在接口及各终端通行做法,后期需要调整为标准做法) var exception = actionExecutedContext.Exception; if (exception is BusinessException) //业务异常,一般不需记录日志,直接反馈错误信息至前端 { actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.OK, Utils.AssembleMsg(exception.Message)); } else if (exception is OperationCanceledException)//ThirdParty/GetMobilePlace 处理已取消该操作异常 { actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.OK, Utils.AssembleMsg("客户端取消了这次请求")); } else //未处理异常如数据库访问出错、代码层面异常等,返回错误信息并记录日志 { actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.OK, Utils.AssembleMsg("服务器处理出错")); LogHelper.Error(typeof(KYExceptionFilter), actionExecutedContext.Request.RequestUri.AbsolutePath, exception); } #endregion } }