首頁 後端開發 C#.Net教程 關於ASP.NET中過濾器、模型綁定的實例詳解

關於ASP.NET中過濾器、模型綁定的實例詳解

May 11, 2017 am 10:38 AM
asp.net mvc 過濾器

本篇文章主要介紹了詳解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 。這種方式做授權,相較於登入成功給CookieSession的好處就是一個介面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(&#39;:&#39;);
      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中過濾器、模型綁定的實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1670
14
CakePHP 教程
1428
52
Laravel 教程
1329
25
PHP教程
1276
29
C# 教程
1256
24
PHP MVC 架構:建立面向未來的 Web 應用程式 PHP MVC 架構:建立面向未來的 Web 應用程式 Mar 03, 2024 am 09:01 AM

引言在當今快速發展的數位世界中,建立健壯、靈活且可維護的WEB應用程式至關重要。 PHPmvc架構提供了實現這一目標的理想解決方案。 MVC(模型-視圖-控制器)是一種廣泛使用的設計模式,可將應用程式的各個方面分離為獨立的元件。 MVC架構的基礎MVC架構的核心原理是分離關注點:模型:封裝應用程式的資料和業務邏輯。視圖:負責呈現資料並處理使用者互動。控制器:協調模型和視圖之間的交互,管理使用者請求和業務邏輯。 PHPMVC架構phpMVC架構遵循傳統MVC模式,但也引進了語言特定的功能。以下是PHPMVC

Vue報錯:無法正確使用filters中的過濾器,怎麼解決? Vue報錯:無法正確使用filters中的過濾器,怎麼解決? Aug 26, 2023 pm 01:10 PM

Vue報錯:無法正確使用filters中的過濾器,怎麼解決?引言:在Vue中,過濾器(filters)是常用的功能,可以用來格式化資料或過濾。然而,在使用過程中,有時我們可能會遇到無法正確使用過濾器的問題。本文將介紹一些常見的原因和解決方法。一、原因分析:過濾器未正確註冊:Vue中的過濾器需要先註冊,才能在模板中使用。如果過濾器未成功註冊,

PHP MVC 架構的進階指南:解鎖進階功能 PHP MVC 架構的進階指南:解鎖進階功能 Mar 03, 2024 am 09:23 AM

mvc架構(模型-視圖-控制器)是PHP開發中最受歡迎的模式之一,因為它為組織程式碼和簡化WEB應用程式的開發提供了清晰的結構。雖然基本的MVC原理對於大多數Web應用程式來說已經足夠,但對於需要處理複雜資料或實現高級功能的應用程序,它存在一些限制。分離模型層分離模型層是高階MVC架構常見的技術。它涉及將模型類分解為較小的子類,每個子類專注於特定功能。例如,對於一個電子商務應用程序,您可以將主模型類別分解為訂單模型、產品模型和客戶模型。這種分離有助於提高程式碼的可維護性和可重複使用性。使用依賴注入依賴

PHP電子郵件過濾器:過濾並辨識垃圾郵件。 PHP電子郵件過濾器:過濾並辨識垃圾郵件。 Sep 19, 2023 pm 12:51 PM

PHP電子郵件過濾器:過濾並辨識垃圾郵件。隨著電子郵件的廣泛應用,垃圾郵件的數量也不斷增加。對於用戶來說,接收到的大量垃圾郵件會導致資訊過載和時間浪費。因此,我們需要一種高效的方法來過濾和識別垃圾郵件。本文將介紹如何使用PHP編寫一個簡單但有效的電子郵件篩選器,並提供具體的程式碼範例。郵件過濾器基本原理郵件過濾器的基本原理是透過分析郵件的內容和屬性,判斷其是否

Vue技術開發中如何進行資料篩選與排序 Vue技術開發中如何進行資料篩選與排序 Oct 09, 2023 pm 01:25 PM

Vue技術開發中如何進行資料篩選和排序在Vue技術開發中,資料篩選和排序是非常常見且重要的功能。透過資料篩選和排序,我們可以快速查詢和展示我們需要的信息,提高用戶體驗。本文將介紹在Vue中如何進行資料篩選和排序,並提供具體的程式碼範例,幫助讀者更好地理解和運用這些功能。一、資料篩選資料篩選是指依照特定的條件篩選出符合要求的資料。在Vue中,我們可以透過comp

Vue3中的過濾器函數:優雅的處理數據 Vue3中的過濾器函數:優雅的處理數據 Jun 18, 2023 pm 02:46 PM

Vue3中的過濾器函數:優雅的處理資料Vue是一個流行的JavaScript框架,擁有龐大的社群和強大的插件系統。在Vue中,過濾器函數是一種非常實用的工具,允許我們在模板中對資料進行處理和格式化。 Vue3中的過濾器函數有了一些改變,在這篇文章中,我們將深入探討Vue3中的過濾器函數,學習如何使用它們優雅地處理資料。什麼是濾波器函數?在Vue中,過濾器函數是

在PHP中,FILTER_VALIDATE_URL常數表示用於驗證URL的篩選器 在PHP中,FILTER_VALIDATE_URL常數表示用於驗證URL的篩選器 Sep 14, 2023 am 10:37 AM

FILTER_VALIDATE_URL常數用於驗證URL。標誌FILTER_FLAG_SCHEME_REQUIRED−URL必須符合RFC標準。 FILTER_FLAG_HOST_REQUIRED−URL必須包含主機名稱。 FILTER_FLAG_PATH_REQUIRED−URL必須在網域後面有路徑。 FILTER_FLAG_QUERY_REQUIRED−URL必須有查詢字串。傳回值FILTER_VALIDATE_URL

Vue 中使用插件實現自訂過濾器的技巧 Vue 中使用插件實現自訂過濾器的技巧 Jun 25, 2023 pm 05:01 PM

Vue中使用插件實作自訂過濾器的技巧Vue.js提供了一種方便的方式來處理視圖資料過濾的需求,即過濾器(Filter)。過濾器主要負責將視圖中的資料進行格式化和處理,使資料更加直觀和易於理解。 Vue內建了一些常用的過濾器,例如日期格式化、貨幣格式化等,同時也支援自訂過濾器。本文將介紹如何使用Vue插件實作自訂過濾器的技巧,並提供一些實用的過濾

See all articles