MVC的行为过滤器特性(FilterAttribute)扩展
- 扩展ActionFilterAttribute
- 扩展IActionFilter
扩展ActionFilterAttribute
其内部依然是实现了IActionFilter的接口,并以虚函数可重写的形式进行.如下:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
{
protected ActionFilterAttribute();
public virtual void OnActionExecuted(ActionExecutedContext filterContext);
public virtual void OnActionExecuting(ActionExecutingContext filterContext);
public virtual void OnResultExecuted(ResultExecutedContext filterContext);
public virtual void OnResultExecuting(ResultExecutingContext filterContext);
}
该基类ActionFilterAttribute
实现了IActionFilter
和IResultFilter
两个接口.
如下:
public interface IActionFilter
{
void OnActionExecuted(ActionExecutedContext filterContext);
void OnActionExecuting(ActionExecutingContext filterContext);
}
public interface IResultFilter
{
void OnResultExecuted(ResultExecutedContext filterContext);
void OnResultExecuting(ResultExecutingContext filterContext);
}
两个接口中的函数
- Action 在执行控制器方法中和方法后进行调用.
- Result在渲染前端视图中和选然后调用.
public class CustomActionFilterAttribute:ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
cw($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}OnActionExecuted");
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
cw($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}OnActionExecuting");
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
cw($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}OnResultExecuted");
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
cw($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}OnResultExecuting");
}
}
运行过程中顺序是:OnActionExecuting->执行控制器->OnActionExecuted->OnResultExecuting->渲染视图->OnResultExecuted
IActionFilter和IResultFilter
其实上述的两个Attribute都是实现了这两个接口,由于是特性,所以仅仅继承Attribute是无效的.
无效
public class CustomActionFilterAttribute2 : /*Filter*/Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
cw($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}OnActionExecuted");
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
cw($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}OnActionExecuting");
}
}
其原因在于这里Attribute是继承自FilterAttribute,又实现了IMvcFilter接口.
能干啥?
日志记录,任何一个位置都会有不可预料的错误发生.最重要的是,浏览器和服务器在进行请求响应操作时,是需要一定的数据传送的.传送的长短就会直观反映到响应的速度上.
在需要关注点的位置上进行编写.
数据压缩上,那就是在执行OnActionExecuting时要做的.
public void OnActionExecuting(ActionExecutingContext filterContext)
{
//获取浏览器和服务器同时支持的压缩规则.
var request=filterContext.HttpContext.Request;
var response=filterContext.HttpContext.Response;
//获取浏览器支持的压缩格式.
string accept_ecode=request.Headers["Accept-Encoding"];
if(!string.IsNullOrWhiteSpace(accept_ecode)&&accept_ecode.ToUpper().Contains("GZIP")){
response.AddHeader("Content-Encoding","gzip");//设置服务器响应头解压方式.
response.Filter=new GZipStream(response.Filter,CompressionMode.Compress);//压缩类型指定.
//日志记录.log4net
myLogger.Info($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}OnActionExecuting");
}
}
属性的注册方式
- 全局注册(在App_Start/FilterConfig.cs进行)
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); //整个项目都将应用. filters.Add(new CustomActionFilterAttribute()); }
- 标记在控制器上(所有Action都将应用)
[CustomActionFilterAttribute] public class CustomController{}
- 标记在Action上.只对此action生效.
ExceptionFilter
异常Filter
常规操作:try-catch包裹,代码冗余.
- HandlerErrorAttribute
- IExceptionFilter
HandleErrorAttribute扩展
重写或实现
public virtual void OnException(ExceptionContext filterContext){
if(!filterContext.ExceptionHandler){
//处理异常.
//1.如果是访问页面,展示一个页面出去,报出异常消息.
//2.ajax请求,响应一个json格式的数据出去.
if(filterContext.HttpContext.Request.IsAjaxRequest()){//是否为Ajax请求.
filterContext.Result=new JsonResult(){
Data=new{
DebugMessage=filterContext.Exception.Message,
RetValue="",
PromptMsg="发生错误,请联系管理员"
}
};
}
else{
filterContext.Result=new ViewResult(){
ViewName="",//指定错误页面.
ViewData=new ViewDataDictionary<string>(filterContext.Exception.Message)//错误消息.
};
}
filterContext.ExceptionHandler=true;
}
但依然会存在异常捕捉不到的,上面的更偏向于业务异常方面.若访问一个不该访问的页面,上述方法页无能为力了.
需要在Global.asax(全局处理)中进行
///响应!=200,被这里捕捉.
protected void App_err(object s,EventArgs e){
Exception ex=Server.GetLastError();//获取最后的响应错误.
Response.Write();//返回一个错误页面.
Server.ClearError();
}