在asp.net mvc 中 webapi 和 mvc 处理消息是两个不同的管道,Asp.net mvc 和 webapi 为我们提供的 ActionFilterAttribute 拦截器,通过 重写 OnActionExecuting,来 拦截action的请求消息,当执行OnActionExecuting完成以后才真正进入请求的action中,action运行完后又把控制权给了 OnActionExecuted,这个管道机制可以使我们用它来轻松实现 权限认证、日志记录 ,跨域以及很多需要对全局或者部分请求做手脚的的功能。
大概的流程如下
通过ActionFilterAttribute ,就能拦截action 处理的所有内容,包括请求提交的参数以及返回值。由于asp.net MVC 与webapi 是两个完全独立的管道:
- MVC由System.Web.Mvc.ActionFilterAttribute 来做action请求的拦截。
- webapi 由 System.Web.Http.Filters.ActionFilterAttribute 来处理。
因此拦截action请求是完全不相干的两个通道,于此同时,当我们需要注册全局的ActionFilterAttribute 这两个也是分开注册的:
MVC 直接在System.Web.Mvc.GlobalFilterCollection 这个全局管道里面注册 ActionFilter ,位置在App_Start目录>FilterConfig 类>RegisterGlobalFilters 方法 使用参数filters , filters.Add(new YourMvcAttribute()) 添加你的mvc ActionFilterAttribute 。
WebAPI 在System.Web.Http.Filters 中注册, 在项目的App_Start 目录>WebApiConfig类中>Register 方法中加入使用 config参数, config.Filters.Add(new YourWebApiAttribute()); 添加你的 webapi ActionFilterAttribute
这样就可以注册你的 ActionFilterAttribute 成为全局的Filter,系统中请求经过Action 之前或之后 都会被你的ActionFilter 拦下来做处理然后在转交下去。
好了道理已经讲完了,现在开始我自己要实现的 日志记录功能,
需求是记录所有访问webapi action的(请求地址、内容、访问用户、提交的参数、返回的结果、以及一些客户端的信息)
由于MVC 框架 提倡契约编程,在你自定义的Attribute 时,需要遵守契约规范, 【YourFilterName】+Attribute ,所以我的filter名字为 LogAttribute
一、定义过滤器
- /// <summary>
- /// 全局日志过滤器(在WebApiConfig中注册),每个action执行都会执行该过滤器
- /// </summary>
- public class LogAttribute : ActionFilterAttribute
- {
- public override void OnActionExecuting(HttpActionContext filterContext)
- {
- if (!SkipLogging(filterContext))
- {
- //获取action名称
- string actionName = filterContext.ActionDescriptor.ActionName;
- //获取Controller 名称
- string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
- //获取触发当前方法的Action方法的所有参数
- var paramss = filterContext.ActionArguments;
- string Content = Newtonsoft.Json.JsonConvert.SerializeObject(paramss);
- LogHelper.GetInstance(" LogFilter").Write(string.Format("OnActionExecuting、控制器:{0},动作:{1},参数:{2}", controllerName, actionName, Content));
- }
- base.OnActionExecuting(filterContext);
- }
- public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
- {
- if (!SkipLogging(actionExecutedContext.ActionContext))
- {
- //获取action名称
- string actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName;
- //获取Controller 名称
- string controllerName = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
- //获取触发当前方法的Action方法的所有参数
- var paramss = actionExecutedContext.ActionContext.ActionArguments;
- string Content = Newtonsoft.Json.JsonConvert.SerializeObject(paramss);
- LogHelper.GetInstance(" LogFilter").Write(string.Format("OnActionExecuted、控制器:{0},动作:{1},参数:{2}", controllerName, actionName, Content));
- }
- base.OnActionExecuted(actionExecutedContext);
- }
- /// <summary>
- /// 判断控制器和Action是否要进行拦截(通过判断是否有NoLogAttribute过滤器来验证)
- /// </summary>
- /// <param name="actionContext"></param>
- /// <returns></returns>
- private static bool SkipLogging(HttpActionContext actionContext)
- {
- return actionContext.ActionDescriptor.GetCustomAttributes<NoLogAttribute>().Any() || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<NoLogAttribute>().Any();
- }
- }
- /// <summary>
- /// 不需要日志记录的过滤器
- /// </summary>
- [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
- public class NoLogAttribute : Attribute
- {
- }
二、在WebApiConfig.cs中注册全局过滤器
- public static class WebApiConfig
- {
- public static void Register(HttpConfiguration config)
- {
- config.Filters.Add(new LogAttribute());
- config.Routes.MapHttpRoute(
- name: "DefaultApi",
- routeTemplate: "api/{controller}/{action}/{id}",
- defaults: new { id = RouteParameter.Optional }
- );
- }
- }
三、在控制器中使用
- // GET api/sodetails/5
- public string Get(int id)
- {
- return "{\"Value\":\"" + id + "\"}";
- }
- [NoLog]
- public string Post([FromBody]string value) //该action不添加日志信息
- {
- return "{\"Value\":\"" + value + "\"}";
- }
四、日志效果
- 2018/5/14 14:11:11636619038710767426
- L_Message : OnActionExecuting、控制器:SoDetails,动作:Get,参数:{"id":123}
- L_Level : INFO
- L_Folder : LogFilter
- L_CreatTime : 2018-05-14 14:11:11.075
- L_ServerHostName : sh-ysl-bi-hzq
- L_ServerHostIP : 10.10.40.5
- ---------------------------------------
- 2018/5/14 14:11:14636619038740781337
- L_Message : OnActionExecuted、控制器:SoDetails,动作:Get,参数:{"id":123}
- L_Level : INFO
- L_Folder : LogFilter
- L_CreatTime : 2018-05-14 14:11:14.078
- L_ServerHostName : sh-ysl-bi-hzq
- L_ServerHostIP : 10.10.40.5
- ---------------------------------------
全局过滤器
https://www.cnblogs.com/hnsongbiao/p/8717553.html
有时我们想有些公共的方法需要每个Action都执行,但是又不想再每一个Controller上都打上Action标签,怎么办?幸好Asp。Net MVC3带
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
//注册全局过滤器
filters.Add(new TestFilterAttribute() { Message="全局"});
}
这样就每个Action都会执行此过滤器,而不必每个Controller顶部都加上标签。
注意:如前面所述,在WebAPI中则是在System.Web.Http.Filters 中注册, 在项目的App_Start 目录>WebApiConfig类中>Register 方法中加入使用 config参数, config.Filters.Add(new YourWebApiAttribute()); 添加你的 webapi ActionFilterAttribute
这样就可以注册你的 ActionFilterAttribute 成为全局的Filter。