欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MVC 过滤器使用 ActionFilterAttribute

程序员文章站 2022-07-15 10:39:05
...

         在asp.net mvc 中 webapi 和 mvc 处理消息是两个不同的管道,Asp.net mvc 和 webapi 为我们提供的 ActionFilterAttribute 拦截器,通过 重写 OnActionExecuting,来 拦截action的请求消息,当执行OnActionExecuting完成以后才真正进入请求的action中,action运行完后又把控制权给了 OnActionExecuted,这个管道机制可以使我们用它来轻松实现 权限认证、日志记录 ,跨域以及很多需要对全局或者部分请求做手脚的的功能。

大概的流程如下

MVC 过滤器使用 ActionFilterAttribute

通过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  。

MVC 过滤器使用 ActionFilterAttribute

wepi API 在System.Web.Http.Filters 中注册, 在项目的App_Start 目录>WebApiConfig类中>Register 方法中加入使用 config参数, config.Filters.Add(new YourWebApiAttribute()); 添加你的 webapi ActionFilterAttribute 

MVC 过滤器使用 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
---------------------------------------