Maison >développement back-end >Tutoriel C#.Net >Explication détaillée d'exemples de filtres et de liaison de modèles dans ASP.NET
Cet article présente principalement en détail les points d'extension courants d'ASP.NET MVC : filtres et liaison de modèle. Il est d'une grande valeur pratique. Les amis dans le besoin peuvent s'y référer
. 1. Filtre (Filtre)
Chaque requête dans ASP.NET MVC sera affectée à une action spécifique (ci-après dénommée "Méthode") sous le contrôleur correspondant (ci-après dénommé "Controller") ), dans des circonstances normales, écrivez simplement le code directement dans la méthode, mais si vous souhaitez traiter une certaine logique avant ou après l'exécution de la méthode, vous devez utiliser des filtres ici.
Il existe trois filtres couramment utilisés : Authorize (filtre d'autorisation), HandleError (filtre d'exception), ActionFilter (filtre personnalisé), et les classes correspondantes sont : AuthorizeAttribute, HandleErrorAttribute et ActionFilterAttribute, Inherit ces classes et remplacez leurs méthodes pour réaliser différentes fonctions.
1.Autoriser le filtre d'autorisation
Comme son nom l'indique, le filtre d'autorisation est utilisé pour l'autorisation. Le filtre d'autorisation est exécuté avant l'exécution de la méthode pour limiter si le filtre d'autorisation est exécuté. requête peut saisir cette méthode, créez une nouvelle méthode :
public JsonResult AuthorizeFilterTest() { return Json(new ReturnModel_Common { msg = "hello world!" }); }
Accès direct pour obtenir le résultat :
En supposant maintenant que cette méthode AuthorizeFilterTest est une Méthode d'arrière-plan, l'utilisateur doit en avoir un. Seul un jeton valide est accessible. L'approche conventionnelle consiste à recevoir et à vérifier le jeton dans la méthode AuthorizeFilterTest. Cependant, une fois qu'il existe de nombreuses méthodes, il est évidemment peu pratique d'écrire du code de vérification dans chaque méthode. . À ce stade, une autorisation est nécessaire. Filtre :
public class TokenValidateAttribute : AuthorizeAttribute { /// <summary> /// 授权验证的逻辑处理。返回true则通过授权,false则相反 /// </summary> /// <param name="httpContext"></param> /// <returns></returns> protected override bool AuthorizeCore(HttpContextBase httpContext) { string token = httpContext.Request["token"]; if (string.IsNullOrEmpty(token)) { return false; } else { return true; } } }
Créez une nouvelle classe qui hérite de AuthorizeAttribute et réécrivez la méthode AuthorizeCore. Ce pseudo-code implémente que si le jeton a une valeur, il renvoie vrai. , sinon, il renvoie false. Marquez-le comme Méthodes nécessitant une autorisation d'accès :
[TokenValidate] public JsonResult AuthorizeFilterTest() { return Json(new ReturnModel_Common { msg = "hello world!" }) }
Après avoir marqué TokenValidate, la méthode AuthorizeCore est exécutée avant AuthorizeFilterTest. Si AuthorizeCore renvoie true, l'autorisation exécute avec succès le code. dans AuthorizeFilterTest, sinon l'autorisation échoue. Ne pas transmettre le jeton :
Passer le jeton :
Ne pas transmettre le jeton Lorsque l'autorisation échoue, MVC par défaut n'est pas autorisé. est entrée. Apportons une amélioration ici : que l'autorisation soit réussie ou échouée, le format de la valeur de retour doit être cohérent pour faciliter le traitement frontal. À ce stade, réécrivez simplement la méthode HandleUnauthorizedRequest dans la classe AuthorizeAttribute :
/// <summary> /// 授权失败处理 /// </summary> /// <param name="filterContext"></param> protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); var json = new JsonResult(); json.Data = new ReturnModel_Common { success = false, code = ReturnCode_Interface.Token过期或错误, msg = "token expired or error" }; json.JsonRequestBehavior = JsonRequestBehavior.AllowGet; filterContext.Result = json; }.
Effet :
Pratique : L'application la plus utilisée du filtre d'autorisation est le système de gestion des droits Après la connexion de l'utilisateur. avec succès, le serveur génère un jeton crypté. Les requêtes suivantes apporteront ce jeton. Le serveur déverrouille le jeton dans la méthode AuthorizeCore pour obtenir l'ID utilisateur. En fonction de l'ID utilisateur, il accède à la base de données pour vérifier s'il existe. autorisation de demander l'interface actuelle Si tel est le cas, elle renvoie vrai, sinon renvoie faux. L'avantage d'utiliser cette méthode d'autorisation par rapport à une connexion réussie à Cookie et Session est qu'une seule interface peut être utilisée à la fois côté PC et côté application.
2. Filtre d'exception HandleError
Le filtre d'exception gère les exceptions de code et est exécuté lorsque le code système renvoie une erreur par défaut et est enregistré auprès de MVC. FilterConfig.cs dans le répertoire App_Start :
filters.Add(new HandleErrorAttribute());
Ceci est efficace pour l'ensemble du système. Toute erreur d'interface ou de page exécutera la Gestion des exceptions par défaut de MVC et renverra une page d'erreur par défaut : Vues. /Partagé/Erreur (cette page ne peut être vue que lorsque le programme est envoyé au serveur pour signaler une erreur. Si le débogage local a des autorisations élevées, vous pouvez toujours voir les informations d'erreur spécifiques)
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width" /> <title>错误</title> </head> <body> <hgroup> <h1>错误。</h1> <h2>处理你的请求时出错。</h2> </hgroup> </body> </html>
Le filtre d'exception par défaut ne peut évidemment pas répondre aux besoins d'utilisation. Le filtre d'exception a été réécrit pour répondre aux besoins réels du projet :
1) Le rapport d'erreurs peut enregistrer le contrôleur et la méthode où le le code d'erreur est localisé, et les Paramètres de la demande et l'heure lors du signalement d'une erreur
2) Renvoie JSON dans un format spécifique pour faciliter le traitement frontal ; Étant donné que la plupart du système utilise désormais des requêtes ajax, si une erreur est signalée, il revient à la page d'erreur par défaut de MVC, ce qui est difficile à gérer sur le front-end
Créez une nouvelle classe LogExceptionAttribute qui hérite de HandleErrorAttribute, et remplace la méthode interne OnException :
public override void OnException(ExceptionContext filterContext) { if (!filterContext.ExceptionHandled) { string controllerName = (string)filterContext.RouteData.Values["controller"]; string actionName = (string)filterContext.RouteData.Values["action"]; string param = Common.GetPostParas(); string ip = HttpContext.Current.Request.UserHostAddress; LogManager.GetLogger("LogExceptionAttribute").Error("Location:{0}/{1} Param:{2}UserIP:{3} Exception:{4}", controllerName, actionName, param, ip, filterContext.Exception.Message); filterContext.Result = new JsonResult { Data = new ReturnModel_Common { success = false, code = ReturnCode_Interface.服务端抛错, msg = filterContext.Exception.Message }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } if (filterContext.Result is JsonResult) filterContext.ExceptionHandled = true;//返回结果是JsonResult,则设置异常已处理 else base.OnException(filterContext);//执行基类HandleErrorAttribute的逻辑,转向错误页面 }
异常过滤器就不像授权过滤器一样标注在方法上面了,直接到App_Start目录下的FilterConfig.cs注册下,这样所有的接口都可以生效了:
filters.Add(new LogExceptionAttribute());
异常过滤器里使用了NLog作为日志记录工具,Nuget安装命令:
Install-Package NLog Install-Package NLog.Config
相比Log4net,NLog配置简单,仅几行代码即可,NLog.config:
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <targets> <target xsi:type="File" name="f" fileName="${basedir}/log/${shortdate}.log" layout="${uppercase:${level}} ${longdate} ${message}" /> <target xsi:type="File" name="f2" fileName="D:\log\MVCExtension\${shortdate}.log" layout="${uppercase:${level}} ${longdate} ${message}" /> </targets> <rules> <logger name="*" minlevel="Debug" writeTo="f2" /> </rules> </nlog>
如果报错,日志就记录在D盘的log目录下的MVCExtension目录下,一个项目一个日志目录,方便管理。全部配置完成,看下代码:
public JsonResult HandleErrorFilterTest() { int i = int.Parse("abc"); return Json(new ReturnModel_Data { data = i }); }
字符串强转成int类型,必然报错,页面响应:
同时日志也记录下来了:
3.ActionFilter自定义过滤器
自定义过滤器就更加灵活了,可以精确的注入到请求前、请求中和请求后。继承抽象类ActionFilterAttribute并重写里面的方法即可:
public class SystemLogAttribute : ActionFilterAttribute { public string Operate { get; set; } public override void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write("<br/>" + Operate + ":OnActionExecuted"); base.OnActionExecuted(filterContext); } public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write("<br/>" + Operate + ":OnActionExecuting"); base.OnActionExecuting(filterContext); } public override void OnResultExecuted(ResultExecutedContext filterContext) { filterContext.HttpContext.Response.Write("<br/>" + Operate + ":OnResultExecuted"); base.OnResultExecuted(filterContext); } public override void OnResultExecuting(ResultExecutingContext filterContext) { filterContext.HttpContext.Response.Write("<br/>" + Operate + ":OnResultExecuting"); base.OnResultExecuting(filterContext); } }
这个过滤器适合做系统操作日志记录功能:
[SystemLog(Operate = "添加用户")] public string CustomerFilterTest() { Response.Write("<br/>Action 执行中..."); return "<br/>Action 执行结束"; }
看下结果:
四个方法执行顺序:OnActionExecuting—>OnActionExecuted—>OnResultExecuting—>OnResultExecuted,非常精确的控制了整个请求过程。
实战中记录日志过程是这样的:在OnActionExecuting方法里写一条操作日志到数据库里,全局变量存下这条记录的主键,到OnResultExecuted方法里说明请求结束了,这个时候自然知道用户的这个操作是否成功了,根据主键更新下这条操作日志的是否成功字段。
二、模型绑定(ModelBinder)
先看一个普通的方法:
public ActionResult Index(Student student) { return View(); }
这个方法接受的参数是一个Student对象,前端传递过来的参数跟Student对象里的属性保持一直,那么就自动被绑定到这个对象里了,不需要在方法里new Student这个对象并挨个绑定属性了,绑定的过程由MVC中的DefaultModelBinder完成的,DefaultModelBinder同时继承了IModelBinder接口,现在就利用IModelBinder接口和DefaultModelBinder来实现更加灵活的模型绑定。
场景一、前端传过来了一个加密的字符串token,方法里需要用token里的某些字段,那就得在方法里接收这个字符串、解密字符串、转换成对象,这样一个方法还好说,多了的话重复代码非常多,就算提取通用方法,还是要在方法里调用这个通用方法,有没有办法直接在参数里就封装好这个对象?
模型绑定的对象:
public class TokenModel { /// <summary> /// 主键 /// </summary> public int Id { get; set; } /// <summary> /// 姓名 /// </summary> public string Name { set; get; } /// <summary> /// 简介 /// </summary> public string Description { get; set; } }
新建一个TokenBinder继承IModelBinder接口并实现其中的BindModel方法:
public class TokenBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var token = controllerContext.HttpContext.Request["token"]; if (!string.IsNullOrEmpty(token)) { string[] array = token.Split(':'); if (array.Length == 3) { return new TokenModel() { Id = int.Parse(array[0]), Name = array[1], Description = array[2] }; } else { return new TokenModel() { Id = 0 }; } } else { return new TokenModel() { Id = 0 }; } } }
这个方法里接收了一个token参数,并对token参数进行了解析和封装。代码部分完成了需要到Application_Start方法里进行下注册:
ModelBinders.Binders.Add(typeof(TokenModel), new TokenBinder());
现在模拟下这个接口:
public JsonResult TokenBinderTest(TokenModel tokenModel) { var output = "Id:" + tokenModel.Id + ",Name:" + tokenModel.Name + ",Description:" + tokenModel.Description; return Json(new ReturnModel_Common { msg = output }); }
调用下:
可以看出,“1:汪杰:oppoic.cnblogs.com”已经被绑定到tokenModel这个对象里面了。但是如果稍复杂的模型绑定IModelBinder就无能为力了。
场景二、去除对象某个属性的首位空格
public class Student { public int Id { get; set; } public string Name { get; set; } public string Class { get; set; } }
如果前端传来的Name属性有空格,如何去除呢?利用DefaultModelBinder即可实现更灵活的控制
public class TrimModelBinder : DefaultModelBinder { protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) { var obj = base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder); if (obj is string && propertyDescriptor.Attributes[typeof(TrimAttribute)] != null)//判断是string类型且有[Trim]标记 { return (obj as string).Trim(); } return obj; } }
标注下需要格式化首位属性的实体:
[ModelBinder(typeof(TrimModelBinder))] public class Student { public int Id { get; set; } [Trim] public string Name { get; set; } public string Class { get; set; } }
好了,测试下:
public JsonResult TrimBinderTest(Student student) { if (string.IsNullOrEmpty(student.Name) || string.IsNullOrEmpty(student.Class)) { return Json(new ReturnModel_Common { msg = "未找到参数" }); } else { return Json(new ReturnModel_Common { msg = "Name:" + student.Name + ",长度:" + student.Name.Length + " Class:" + student.Class + ",长度:" + student.Class.Length }); } }
可见,标注了Trim属性的Name长度是去除空格的长度:7,而没有标注的Class属性的长度则是6。
【相关推荐】
2. ASP.NET教程
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!