旗下导航:搜·么
当前位置:网站首页 > .Net教程 > 正文

关于ASP.NET中过滤器、模子绑定的实例详解【C#.Net教程】,asp.net,mvc,模型绑定,asp.net,mvc,过滤器,mvc,模型绑定

作者:搜教程发布时间:2019-11-27分类:.Net教程浏览:92评论:0


导读:本篇文章重要引见了详解ASP.NETMVC经常运用扩大点:过滤器、模子绑定,非常具有实用价值,须要的朋侪能够参考下一、过滤器(Filter)ASP.NETMVC中...
本篇文章重要引见了详解ASP.NET MVC 经常运用扩大点:过滤器、模子绑定,非常具有实用价值,须要的朋侪能够参考下

一、过滤器(Filter)

ASP.NET MVC中的每一个要求,都邑分配给对应Controller(以下简称“掌握器”)下的特定Action(以下简称“要领”)处置惩罚,一般状况下直接在要领里写代码就能够了,然则假如想在要领实行之前或许以后处置惩罚一些逻辑,这里就须要用到过滤器。

经常运用的过滤器有三个:Authorize(受权过滤器),HandleError(非常过滤器),ActionFilter(自定义过滤器),对应的类分别是:AuthorizeAttribute、HandleErrorAttribute和ActionFilterAttribute,继续这些类并重写个中要领即可完成差别的功用。

1.Authorize受权过滤器

受权过滤器望文生义就是受权用的,受权过滤器在要领实行之前实行,用于限定要求能不能进入这个要领,新建一个要领:

public JsonResult AuthorizeFilterTest()
{
 return Json(new ReturnModel_Common { msg = "hello world!" });
}

直接接见获得结果:

如今假定这个AuthorizeFilterTest要领是一个背景要领,用户必需得有一个有用的令牌(token)才接见,通例做法是在AuthorizeFilterTest要领里吸收并考证token,然则如许一旦要领多了,每一个要领里都写考证的代码明显不切实际,这个时刻就要用到受权过滤器:

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;
      }
    }
  }

新建了一个继续AuthorizeAttribute的类,并重写了个中的AuthorizeCore要领,这段伪代码完成的就是token有值即返回true,没有则返回false,标注到须要受权才够接见的要领上面:

[TokenValidate]
public JsonResult AuthorizeFilterTest()
{
  return Json(new ReturnModel_Common { msg = "hello world!" })
}

标注TokenValidate后,AuthorizeCore要领就在AuthorizeFilterTest之前实行,假如AuthorizeCore返回true,那末受权胜利实行AuthorizeFilterTest内里的代码,不然受权失利。不传token:

传token:

不传token受权失利时进入了MVC默许的未受权页面。这里做下革新:不论受权是胜利照样失利都保证返回值花样一致,轻易前端处置惩罚,这个时刻重写AuthorizeAttribute类里的HandleUnauthorizedRequest要领即可:

/// <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;
}

结果:

实战:受权过滤器最普遍的运用照样做权限治理体系,用户登录胜利后服务端输出一个加密的token,后续的要求都邑带上这个token,服务端在AuthorizeCore要领里解开token拿到用户ID,依据用户ID去数据库里查是不是有要求当前接口的权限,有就返回true,反之返回false。这类体式格局做受权,比拟登录胜利给Cookie和Session的优点就是一个接口PC端、App端配合运用。

2.HandleError非常过滤器

非常过滤器是处置惩罚代码非常的,在体系的代码抛错的时刻实行,MVC默许已完成了非常过滤器,而且注册到了App_Start目次下的FilterConfig.cs:

filters.Add(new HandleErrorAttribute());

这个见效于悉数体系,任何接口或许页面报错都邑实行MVC默许的非常处置惩罚,并返回一个默许的报错页面:Views/Shared/Error(递次发到服务器上报错时才够看到本页面,当地调试权限高,照样能够看到细致报错信息的)

@{
  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>

默许的非常过滤器明显没法满足运用需求,重写下非常过滤器,敷衍项目实战中的需求:

1)报错能够纪录毛病代码地点的掌握器和要领,以及报错时的要求参数和时候;

2)返回特定花样的JSON轻易前端处置惩罚。由于如今体系大部份是ajax要求,报错了返回MVC默许的报错页面,前端不优点置惩罚

新建一个类LogExceptionAttribute继续HandleErrorAttribute,并重写内部的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。

【相干引荐】

1. ASP.NET免费视频教程

2. ASP.NET教程

3. 极客学院ASP,NET视频教程

以上就是关于ASP.NET中过滤器、模子绑定的实例详解的细致内容,更多请关注ki4网别的相干文章!

标签:asp.netmvc模型绑定过滤器


欢迎 发表评论: