006_過濾器

?

過濾器

   過濾器(Filter)把附加邏輯注入到MVC框的請求處理,實現了交叉關注。所謂交叉關注(Cross-Cutting Concerns),是指可以用于整個應用程序,而又不適合放置在某個局部位置的功能,否則會打破關注分離模式。典型的例子有:登錄、授權、緩存等等。

使用過濾器

   如果希望動作方法只能被認證用戶所使用,可以在每個動作方法中檢查請求的授權狀態。如在動作方法中使用Request.IsAuthenticated方法明確地檢查授權:if(!Request.IsAuthenticated){如果未被授權,則…}。

   但是,如果在項目中這么做,那會非常繁瑣,他需要在每一個需要有授權認證的動作方法中進行判斷。所以,采用過濾器才是最好的辦法,如清單1:

    // 說明:// 過濾器是 .NET 的注解屬性,可以把它們運用于動作方法或控制器類。// 當被用于控制器類時,其作用效果將覆蓋當前控制器中的每一個方法。
    [Authorize]public class AdminController : Controller{public ViewResult Index(){…}public ViewResult Edit(int productId){…}}

.NET的注解屬性,一個新鮮的事物


?

   注解屬性(Attribute)是派生于System.Attribute的特殊的.NET類。它們可以被附加到其他代碼元素上,包括類、方法、屬性以及字段等。目的是把附加信息嵌入到已編譯的代碼中,以便在運行時讀回這些信息。

   在C#中,注解屬性用方括號進行附加,而且可以用已命名參數語法給它們的public屬性賦值(如:[MyAttribute(SomeProperty=value)])。在C#的編譯器命名約定中,如果這些注解屬性類的名稱以單詞Attribute結尾,則可以忽略這一部分(如,對于AuthorizeAttribute注解屬性,可以寫成[Authorize])。

過濾器的四種基本類型

???????? MVC框架支持四種不同類型的過濾器。分別是:認證過濾器、動作過濾器、結果過濾器、異常過濾器,如下表:

過濾器類型

接口

默認實現

描述

Authorization

(認證過濾器)

IAuthorizationFilter

AuthorizeAtrribute

最先運行,在任何其他過濾器或動作方法之前

Action

(動作過濾器)

IActionFilter

ActionFilterAtrribute

在動作方法之前及之后運行

Result

(結果過濾器)

IResultFilter

ActionFilterAtrribute

在動作結果被執行之前和之后運行

Exception

(異常過濾器)

IExceptionFilter

HandleErrorAtrribute

僅在另一個過濾器、動作方法、或動作結果拋出異常時運行

   在框架調用一個動作之前,會首先檢測該方法的定義,以查看它是否具有這些過濾器設置。如果有,那么便會在請求管道的相應點上調用這些接口所定義的方法。當然,框架默認實現了這些接口。

注:ActionFilterAtrribute類即實現了IActionFilter,也實現了IResultFilter接口,但這是一個抽象類,要求我們必須提供一個實現。

將過濾器運用于控制器和動作方法

   過濾器可以應用于動作方法,也可以運用于整個控制器。清單1,將Authorize過濾器運用于AdminController類,其效果與將其運用于控制器中的每一個方法相同,如清單2:

    public class AdminController : Controller{[Authorize]public ViewResult Index(){…} [Authorize]public ViewResult Edit(int productId){…}}

   可以運用多個過濾器,也可以混搭它們運用的層級——即,將它們運用于整個控制器或某個動作方法。如清單3演示了三個不同過濾器的使用方式:

  [Authorize(Roles="trader")]    // applies to all actions(運用于所有動作)public class ExampleController : Controller{[ShowMessage]    // applies to just this action(僅用于本動作)[OutputCache(Duration=60)]    // applies to just this action(僅用于本動作)public ViewResult Index(){…}}

注:如果為控制器定義了一個自定義基類,那么運用于基類上的任何過濾器都會影響其派生類。

創建示例項目

   為了后面內容的介紹,我們這里利用空模板創建一個名為Filters的項目。在項目中添加一個Home控制器,并將其Index動作方法修改成如下這樣:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Controllers
{public class HomeController : Controller{/// <summary>/// 一個返回字符串值的動作方法,這樣可以使 MVC 繞過 Razor 視圖引擎,直接將字符串值發送給瀏覽器/// (這只是為了簡化,在實際的項目中還是應該使用視圖——這里只關注控制器)/// </summary>/// <returns></returns>public string Index(){return "This is the Index action on the Home Controller";}}
}

???????? 上面的動作方法的返回值修改為字符串型,這樣可以是MVC框架繞過Razor視圖引擎,直接將字符串發送給瀏覽器,這樣做只是為了簡化,因為現在我們只關注控制器。

???????? 該示例的運行結果如圖所示:

? ? ? ? ? ? ? ? ? ? ? ?

使用授權過濾器

   授權過濾器是首先運行的過濾器,而且也在動作方法被調用之前。過濾器通過執行設定的授權策略以確保動作方法只被一人在用戶所調用。授權過濾器需要實現IAuthorizationFilter接口。如:

namespace System.Web.Mvc
{public interface IAuthorizationFilter{void OnAuthorization(AuthorizationContext filterContext);}
}

???????? 當然也可以通過創建實現IAuthorizationFilter接口的類,實現一個自定義的授權過濾器,使用自己的安全邏輯。但是,不建議這樣做,主要原因如下:


警告:編寫安全性代碼的安全性


   一般情況下,自行編寫的安全代碼總會存在一些缺陷,或未經測試的角落,從而留下了一些安全漏洞。

   所以,只要可能,可以使用經過廣泛測試并得到驗證的安全代碼。而且框架也提供了特性完備的授權過濾器,并能夠擴展實現自定義授權策略。

?

   一個更安全的辦法是創建一個AuthorizeAttribute類的子類,讓它照管所有棘手的事情,而且編寫自定義的授權代碼是很容易的。這里為了演示這種方式的實現,在示例項目中添加了一個Infrastructure文件夾,在這個文件夾中我創建了一個新的類文件:CustomAuthAttribute.cs,其內容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Infrastructure
{public class CustomAuthAttribute : AuthorizeAttribute{private bool _localAllowed;public CustomAuthAttribute(bool allowedParam){this._localAllowed = allowedParam;}protected override bool AuthorizeCore(HttpContextBase httpContext){if (httpContext.Request.IsLocal){return this._localAllowed;}else{return true;}}}
}

?

   這是一個簡單的授權過濾器,它實現了阻止本地請求的訪問(所謂本地請求就是一種瀏覽器與應用程序服務器在同一設備上運行而形成的請求,如開發用機)。

???????? 在這個示例中繼承了AuthorizeAttribute類,并重寫了AuthorizeCore方法。這樣即實現了自定義授權的目的,也保證了能夠獲益AuthorizeAttribute的其他內建特性。在構造函數中,使用了一個布爾值,用以指示是否允許本地請求。

???????? 這里重寫的這個AuthorizeCore方法,是MVC框架用以檢查過濾器,是否隊請求進行授權訪問的方式。其接收的參數是HttpContexBase對象,通過該參數可以獲得待處理請求的信息。通過利用AuthorizeAttribute基類的內建特性,只需要關注授權邏輯,并在想要對請求進行授權時,從AuthorizeCore方法中返回true,而再不想授權時返回false。


保持授權注解屬性簡單


?

   以上對AuthorizeCore方法傳遞了一個HttpContextBase對象,該對象所提供的是對請求信息進行訪問的方法,而不是訪問運用該注解屬性的控制器和方法的信息。開發人員直接實現IAuthorizationFilter接口的主要原因,是為了獲得對傳遞給OnAuthorization方法的AuthorizationContext的訪問,通過它可以得到更廣范的信息,包括路由細節,以及當前控制器和動作方法的信息。

   一般是不建議自行實現IAuthorizationFilter接口的,主要是因為不僅編寫自己的安全代碼是不危險的。雖然授權是一種交叉關注,但會在授權注解屬性中建立一些邏輯,這些邏輯會與控制器緊密地耦合在一起,這會破壞關注分離,并導致測試和維護的問題。要盡可能保持授權注解屬性簡單,并關注基于請求的授權——讓授權的上下文來自于運用該注解屬性的地方。

運用自定義授權過濾器

   可以像默認的過濾器那樣使用自定義的授權過濾器,如下演示的這樣(加粗部分):

using Filters.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Controllers
{public class HomeController : Controller{/// <summary>/// 一個返回字符串值的動作方法,這樣可以使 MVC 繞過 Razor 視圖引擎,直接將字符串值發送給瀏覽器/// (這只是為了簡化,在實際的項目中還是應該使用視圖——這里只關注控制器)/// </summary>/// <returns></returns>[CustomAuth(false)]public string Index(){return "This is the Index action on the Home Controller";}}
}

?

   示例中將過濾器構造函數的參數設置為false,表示本地請求將被拒絕訪問Index動作方法。如果運行程序,并在本機瀏覽器進行訪問,則將看到授權被拒絕的結果,如圖:

?

本地請求被自定義授權過濾器拒絕訪問

使用內建的授權過濾器

   內建的授權過濾器:AuthorizeAttribute擁有自己的實現,它將通過AuthorizeCore方法實現常規的授權任務。

   當直接使用AuthorizeAttribute時,可以用這個類的兩個公共屬性來指定授權策略,下表給出了這兩個屬性的簡單介紹:

名稱

類型

描述

Users

string

一個逗號分割的用戶名稱列表,允許這些用戶訪問該動作方法

Roles

string

一個逗號分割的角色列表。為了訪問該動作方法,用戶必須至少是這就角色之一。

   下面是這兩個屬性的使用示例(加粗):

using Filters.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Controllers
{public class HomeController : Controller{/// <summary>/// 一個返回字符串值的動作方法,這樣可以使 MVC 繞過 Razor 視圖引擎,直接將字符串值發送給瀏覽器/// (這只是為了簡化,在實際的項目中還是應該使用視圖——這里只關注控制器)/// </summary>/// <returns></returns>//[CustomAuth(false)][Authorize(Users = "adam,steve,jacqui", Roles = "admin")]public string Index(){return "This is the Index action on the Home Controller";}}
}

?

   上述示例中同時指定了用戶和角色,這表示除非兩個條件都滿足,否則將不授予權限。這里還有一個隱含條件,即該請求已被認證。如果未指定任何用戶或角色,那么任何已被認證的用戶都可以使用這個動作方法。

提示:AuthorizeAttribute處理授權,但不負責認證。但我們可以使用任何ASP.NET內建的認證系統或開發自己的認證系統(建議最好使用內建認證系統)。只要認證系統使用標準的ASP.NET的API,那么,AuthorizeAttribute就能限制對控制器和動作的訪問。

   對于大多數情況,AuthorizeAttribute提供的授權策略已經足夠了。但如果希望實現一些特殊功能,可以通過這個類進行派生。雖然這樣比直接實現IAuthorizationFilter接口的風險要小很多,但在開發的過程中還要非常謹慎的考慮策略的影響,并對它進行充分的測試。

使用異常過濾器

   只有在調用一個動作方法時,如果拋出未處理的異常,異常過濾器才會運行。這種異常的來源主要有以下幾種:

  • 另一個過濾器(授權、動作或結構過濾器);
  • 動作方法本身;
  • 當動作結果被執行時。

創建異常過濾器

   異常過濾器必須實現IExceptionFilter接口,該接口的命名空間為:System.Web.Mvc,其中OnException方法是在發送異常時被調用的。該方法的參數是一個繼承自ControllerContext的ExceptionContext類型的對象,它提供了很多有用的屬性可以用來獲取關于請求的信息,如下表:

名稱

類型

描述

Controller

ControllerBase

返回請求的控制器對象

HttpContext

HttpContextBase

提供對請求細節的訪問,以及對響應的訪問

IsChildAction

bool

若是子動作,便返回true

RequestContext

RequestContext

提供對HttpContext和路由數據的訪問,通過其他屬性,兩者都是可用的

RouteData

RouteData

返回請求的路由數據

   上表中的屬性都是繼承自ControllerContext的,除此之外,它還定義了一些附加屬性,見下表:

名稱

類型

描述

ActionDescriptior

ActionDescriptior

提供動作方法的細節

Result

ActionResult

用于動作方法的結果:通過將該屬性設置為一個非空值過濾器可以取消這個請求

Exception

Exception

未處理異常

ExceptionHandled

bool

如果另一個過濾器已經把這個異常標記為“已處理”,則返回true

   被拋出的異常可以通過Exception屬性進行操作。將ExceptionHandled屬性設置為“true”,異常過濾器可以報告它已經處理了該異常。但即便如此,應用于一個動作的所有異常過濾器還是會被調用,所以,一個比較好的處理方式是檢測另一個過濾器是否已經處理了這個問題,以免恢復另一個過濾器已經解決了的問題。

注:如果一個動作方法的所有異常過濾器均為將ExceptionHandled屬性設置為“true”,MVC框架將使用默認的ASP.NET異常處理器。這將會顯示恐怖的“黃色屏幕”。

   Result屬性由異常過濾器使用,已告訴MVC框架要做什么。異常過濾器的兩個主要用途是對異常進行日志,并將適當的消息顯示給用戶。下面我們通過 類來演示該如何使用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Infrastructure
{public class RangeExceptionAttribute : FilterAttribute, IExceptionFilter{public void OnException(ExceptionContext filterContext){if (!filterContext.ExceptionHandled &&filterContext.Exception is ArgumentOutOfRangeException){filterContext.Result = new RedirectResult("~/Content/RangerErrorPage.html");filterContext.ExceptionHandled = true;}
        }}
}

?

   這里對ArgumentOutOfRangeException實例進行了處理,采取的辦法是將用戶瀏覽器重定向到Content文件夾中名為RangerErrorPage.html文件。

   需要注意該類繼承了FilterAttribute類,此外還實現了IExceptionFilter接口。為了讓一個.NET注解屬性類被視為一個MVC過濾器,該類必須實現IMvcFilter接口。我們可以直接實現該接口,但最簡單的方式是通過FilterAttribute來派生自己的類,它已經實現了所以需要的接口,并提供一些有用的基本特性,如處理過濾器執行的默認處理順序。

運用異常過濾器

   在使用異常過濾器之前還需要前面提到的Content文件夾和RangerErrorPage.html文件(靜態的HTML文件)。在本示例中將使用該文件顯示一些簡單的消息。代碼如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Rang Error</title>
</head>
<body><h2>Sorry</h2><span>One of the arguments was out of the expected range.</span>
</body>
</html>

?

   下面,需要對Home控制器添加一個動作方法,它將拋出我們感興趣的異常。添加的內容如下:

public string RangeTest(int id){if (id > 100){return string.Format("The id value is:{0}", id);}else{throw new ArgumentOutOfRangeException("id", id, "");}}
…

?

   啟動程序,并導航至/Home/RangeTest/50(如我的完整URL是:http://localhost:4081/Home/RangeTest/50),便可以看到默認的異常處理結果。(Visual Studio為MVC項目創建的默認路由中,具有一個名為id的片段變量,針對這一URL,它的值將被設為50,這回得到下圖的響應結果)。

?

   可以將異常過濾器運用于控制器或個別動作,如:

 [RangeException]public string RangeTest(int id){if (id > 100){return string.Format("The id value is:{0}", id);}else{throw new ArgumentOutOfRangeException("id", id, "");}}
…

   在此導航至/Home/RangeTest/50,將得到如下結果:

?

使用視圖來響應異常

   通過顯示靜態內容的頁面來處理異常是簡單且安全的,但這對用戶來說沒有什么用處。——最多也就能得到一個泛泛的警告,最后選擇退出程序。最好的辦法是使用視圖來顯示問題的細節,并為其提供一些上下文信息和選項,以幫助用戶對異常采取處理。

???????? 對于該示例,這里做出了一些調整,將RangeExceptionAttribute類修改成如下這樣(加粗部分和注釋部分為修改內容):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Infrastructure
{public class RangeExceptionAttribute : FilterAttribute, IExceptionFilter{public void OnException(ExceptionContext filterContext){if (!filterContext.ExceptionHandled &&filterContext.Exception is ArgumentOutOfRangeException){int val = (int)(((ArgumentOutOfRangeException)filterContext.Exception).ActualValue);filterContext.Result = new ViewResult{ViewName = "RangeError",ViewData = new ViewDataDictionary<int>(val)};// 下面注釋掉的方式顯示了一個靜態頁面內容//filterContext.Result = new RedirectResult("~/Content/RangerErrorPage.html");filterContext.ExceptionHandled = true;}}}
}

?

???????? 這里創建了一個ViewResult對象,并設置了ViewName和ViewData屬性的值,以指定視圖名稱和要傳遞給視圖的模型對象。這樣寫顯得代碼有些凌亂是直接使用ViewResult對象,而不是在Controller類定義的動作方法中使用View方法的原因。這里我們沒必要關注這些,只要明白如何實現這一效果即可。后面我們會通過內建的異常過濾器更好的實現同樣效果。

???????? 這里我們指定了一個名為RangeError的視圖,并傳了一個int型的參數值,以這個引起異常的參數值作為視圖模型對象。后面,繼續在項目中添加一個Views/Shared文件夾,并創建RangeError.cshtml文件:

@model int<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>Range Error</title>
</head>
<body><h2>The value @Model was out of the expected range.</h2><div>@Html.ActionLink("Change value and try again", "Index")</div>
</body>
</html>

   由于示例功能有限,未向用戶指示出解決這一問題的任何有用信息,但這里使用ActionLink輔助器方法創建了一個指向另一個動作方法的連接,目的是演示可以使用一整套視圖特性。再次啟動程序,并導航至/Home/RangeTest/50,將看到如下效果:

?

   避免異常錯誤陷阱

???????? 使用視圖來顯示錯誤消息的好處是可以使用布局是錯誤消息與應用程序的其余部分一致,并生成動態的內容,幫助用戶了解發生了什么錯誤,以及提示他們可以如何處理問題。

???????? 但是這么做也存在一些缺陷:這就要求我們在開發的過程當中必須徹底的測試視圖,以確保不會產生其他異常。作為簡單示例,這里對RangeError.cshtml視圖添加了一個Razor代碼塊,很明顯它將拋出一個異常,如:

@model int@{// 用來演示在異常視圖信息中拋出異常的情況
    var count = 0;var number = Model / count;
}<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>Range Error</title>
</head>
<body><h2>The value @Model was out of the expected range.</h2><div>@Html.ActionLink("Change value and try again", "Index")</div>
</body>
</html>

   當該視圖被渲染時,將會生成一個DivideByZeroException(被零除異常)。如果啟動程序,并導航至/Home/RangeTest/50,將會看到拋出的異常,該異常是在視圖渲染期間拋出的,且不由控制器拋出。如下圖:

?

   這個演示雖不是真是場景,但它說明了當視圖有問題時發送的情況——用戶看到了一個困惑的錯誤提示,甚至與他們在程序中遇到的問題毫不相關。所以,在使用一個依賴于視圖的異常過濾器時,必須小心謹慎地對視圖進行充分的測試。

使用內建的異常過濾器

   在實際的項目中一般不需要向前面將的那樣去創建自己的過濾器,MVC框架包含了HandleErrorAttribute異常過濾器,它是內建IExceptionFilter接口的實現。該異常過濾器有一些常用的屬性,可以用來指定一個異常以及視圖和布局名稱,詳見下表:

名稱

類型

描述

ExceptionType

Type

由過濾器處理的異常類型。它也處理通過給定值繼承而來的異常類型,但會忽略所有其他類型。其默認值是System.Exception,其含義為,默認地處理所有標準異常

View

string

該過濾器渲染的視圖模板名。如果未指定一個值,則采用默認的Error值,因此,默認情況下會渲染/Views/<currentCotrollerName>/Error.cshtml或/Views/Shared/Error.cshtml

Master

string

在渲染這過濾器的視圖時所使用的布局名稱。如果未指定一個值,該視圖使用其默認布局頁面

   當遇到由ExceptionType指定類型的未處理異常時,此過濾器將渲染由View屬性指定的視圖(使用默認布局,或有Master屬性指定的布局)。

   1.使用內建異常過濾器要做的準備

   只有在Web.config文件中啟用了自定義錯誤時,HandleErrorAttribute過濾器才會生效,這可以在<system.web>節點中添加一個customErrors屬性即可,如:

<system.web><httpRuntime targetFramework="4.5" /><compilation debug="true" targetFramework="4.5" /><pages><namespaces><add namespace="System.Web.Helpers" /><add namespace="System.Web.Mvc" /><add namespace="System.Web.Mvc.Ajax" /><add namespace="System.Web.Mvc.Html" /><add namespace="System.Web.Routing" /><add namespace="System.Web.WebPages" /></namespaces></pages><customErrors mode="On" defaultRedirect="/Content/RangeErrorPage.html"/></system.web>

   model屬性的默認值是RemoteOnly,意為在開發期間,HandleErrorAttribute將不會攔截異常,但將應用程序部署到產品服務器,并從另一臺計算機發出請求時才會生效。為了看到用戶最終將看到的情況,要確保已經將這個自定義錯誤模式設置為“On”。defaultRedirect屬性指定了一個內容頁面,在其他情況下都無法顯示異常消息時,便會使用該頁面。

   2.運營內建的異常過濾器

   下面我們看看該如何使用這一內建的異常過濾器:

[HandleError(ExceptionType = typeof(ArgumentOutOfRangeException), View = "RangeError")]public string RangeTest(int id){if (id > 100){return string.Format("The id value is:{0}", id);}else{throw new ArgumentOutOfRangeException("id", id, "");}}
…

   該示例重建了前面自定義過濾器一樣的情況,即通過將視圖顯示給用戶的方式來處理ArgumentOutOfRangeException異常。

???????? 在渲染視圖時,HandleErrorAttribute過濾器會傳遞一個HandleErrorInfo視圖模型對象,這是一個封裝了異常細節的封裝程序,它提供了可在視圖中使用的附加信息,下表給出了HandleErrorInfo類定義的屬性:

名稱

類型

描述

ActionName

string

返回生成異常的動作方法名稱

ControllerName

string

返回生成異常的控制器名稱

Exception

Exception

返回此異常

   下面將演示如何使用這個模型對象來更新RangeError.cshtml視圖:

<!--使用 HandleErrorInfo 模型對象-->
@model HandleErrorInfo
<!--model int-->@{//// 用來演示在異常視圖信息中拋出異常的情況//var count = 0;//var number = Model / count;// 使用 HandleErrorInfo 模型對象ViewBag.Title = "Sorry,there was a problem!";
}<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>Range Error</title>
</head>
<body>@*<h2>The value @Model was out of the expected range.</h2><div>@Html.ActionLink("Change value and try again", "Index")</div>*@<!--使用 HandleErrorInfo 模型對象--><h2>Sorry</h2><span>The value @(((ArgumentOutOfRangeException)Model.Exception).ActualValue)was out of the expected range.</span><div>@Html.ActionLink("Change value and try again", "Index")</div><!--放在 div 中且將 display 設為 none 可將堆棧的跟蹤情況隱藏--><div style="display:none"><!--必須包含該屬性的值,否則將不能顯示異常視圖-->@Model.Exception.StackTrace</div></body>
</html>

???????? 該視圖中必須將Model.Exception屬性值轉為ArgumentOutOfRangeException類型,以便能夠讀取ActualValue屬性,因為HandleErrorInfo類是一個用來將任何異常傳遞給視圖的一個通用的模型對象。

注意:在使用HandleError過濾器時有一個奇怪的行為,即視圖中必須包含Model. Exception. StackTrace屬性的值,否則視圖便不會顯示給用戶。但因為不想顯示堆棧的跟蹤情況,所以將該值的輸出放在一個div元素中,并將其CSS的display屬性設置為none,使之對用戶是不可見的。

   其效果和使用前述自定義異常過濾器一樣,如圖:

?

使用動作過濾器

   動作過濾器是可以被用于任何目的的多用途過濾器。創建這種過濾器需要實現接口IActionFilter,在MSDN中給出的描述是這樣的:

   命名空間:System.Web.Mvc

   語法:public?interface?IActionFilter

   公開成員(方法):

名稱

說明

語法

OnActionExecuted

在執行操作方法后調用。

void?OnActionExecuted(

????????? ActionExecutedContext?filterContext

)

OnActionExecuting

在執行操作方法之前調用。

void?OnActionExecuting(

????????? ActionExecutingContext?filterContext

)

實現OnActionExecuting方法

   OnActionExecuting方法在調用動作方法之前被調用。可以利用這個機會來檢測請求,并可以在這里取消請求、修改請求,或啟動一些跨越動作調用期間的活動。該方法的參數參加下表的描述:

ActionExecutingContext屬性

名稱

類型

描述

ActionDescriptor

ActionDescriptor

提供動作方法的細節

Result

ActionResult

動作方法的結果:通過將該屬性設置為非空值,過濾器可以取消該請求

   可以用過濾器取消一個請求,這只需將Result參數屬性設置成一個動作結果即可。下面來研究一下該如何實現這一功能,首先在Infrastructure文件夾中創建一個自己的動作過濾器類,名為:CustomActionArribute,如:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Infrastructure
{public class CustomActionArribute : FilterAttribute, IActionFilter{public void OnActionExecuting(ActionExecutingContext filterContext){if (filterContext.HttpContext.Request.IsLocal){filterContext.Result = new HttpNotFoundResult();}}/// <summary>/// /// </summary>/// <param name="filterContex"></param>/// <remarks>/// 如果不需要實現任何邏輯,則空著即可。注意不要拋出 NotImplementedExcetion 異常 —— 否則 MVC 將觸發異常過濾器/// </remarks>public void OnActionExecuted (ActionExecutedContext filterContex){// 尚未實現
}}
}

   上面示例代碼中,用OnActionExceuting方法檢查請求是否來自本地機器。如果是,便對用戶返回一個“404 —— 未找到”的響應。

???????? 動作過濾器的運用和其他注解屬性一樣。為了演示剛剛創建的自定義的動作過濾器,我們需要在Home控制器添加一個新的動作方法,如:

[CustomAction]public string FilterTest(){return "This is the FilterTest action";}
…

   此時,啟動程序并導航至/Home/FilterTest,將得到預期的效果,如果是本地請求將看到如下圖所示結果:

?

實現OnActionExecuted方法

   用動過濾器還可以執行一些跨動作方法執行的任務,下面就看看該如何實現這一效果(需要新建一個動作過濾器類:ProfileActionAttribute):

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Infrastructure
{public class ProfileActionAttribute : FilterAttribute, IActionFilter{private Stopwatch timer;public void OnActionExecuting(ActionExecutingContext filterContext){timer = Stopwatch.StartNew();}public void OnActionExecuted(ActionExecutedContext filterContex){timer.Stop();if (filterContex.Exception == null){filterContex.HttpContext.Response.Write(string.Format("<div>Action method elapsed time: {0}</div>", timer.Elapsed.TotalSeconds));}}}
}

   這里,在OnActionExecuting方法中啟動了一個計時器,在動作方法完成之后MVC框架會調用OnActionExecuted方法——其中執行了關閉計時器并打印執行動作方法所耗時間的信息。

???????? 下面是使用這一過濾器的實例:

// ProfileAction:演示 ProfileAction 過濾器對于耗時測量的效果
        [ProfileAction]//[CustomAction]public string FilterTest(){return "This is the FilterTest action";}
…

   現在就可以看到這一過濾器的效果了:

?

提示:頁面中顯示的耗時信息在動作方法結果被處理之前,是因為動作過濾器是在動作方法完成之后,但在結果被處理之前執行的。也就是說這一時間信息不包括對動作結果處理的時間。

   ActionExecutedContext類型參數的一些屬性的描述詳見下表(其中Exception屬性返回動作方法拋出的異常,而ExceptionHandled屬性只是另一個過濾器是否已經處理了這個異常):

ActionExecutedContext屬性

名稱

類型

描述

ActionDescriptor

ActionDescriptor

提供動作方法的細節

Canceled

bool

如果該動作方法已經被另一個過濾器取消,則返回true

Exception

Exception

返回由另一個過濾器或動作方法拋出的異常

ExceptionHandled

bool

如果異常已經被處理,則返回true

Result

ActionResult

動作方法的結果:通過把這個屬性設置為一個非空值,過濾器可以取消這個請求

   如果另一個過濾器已經取消了這個請求(通過對Result屬性設置一個值的辦法),從OnActionExecuting方法被調用的時刻開始,Canceled屬性便會返回“true”。這仍會調用OnActionExecuted方法,但只是為了清理和釋放已被占用的資源。

使用結果過濾器

   結果過濾器顧名思義,就是要對動作方法產生的結果進行操作,同時它也是多用途過濾器。結果過濾器需要實現IResultFilter接口:

   命名空間:System.Web.Mvc

???????? 語法:public?interface?IResultFilter

???????? 方法:

名稱

說明

語法

OnResultExecuted

在操作結果執行后調用。

void OnResultExecuted(

????????? ResultExecutedContext ? filterContext

)

OnResultExecuting

在操作結果執行之前調用。

void ? OnResultExecuting(

????????? ResultExecutingContext filterContext

)

   可以將動作方法的意圖與動作方法的執行分離開來。將結果過濾器運用于一個動作方法時,會在動作方法返回動作結果之時、但在執行該動作結果之前,調用(結果過濾器的)OnResultExecuting方法。動作結果被執行之后,會調用OnResultExecuted方法。

???????? 下面我們通過在Infrastructure文件夾中創建一個名為ProfileResultAttribute的類來演示一個簡單的過濾器:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Infrastructure
{public class ProfileResultAttribute : FilterAttribute, IResultFilter{private Stopwatch timer;public void OnResultExecuting(ResultExecutingContext filterContext){timer = Stopwatch.StartNew();}public void OnResultExecuted(ResultExecutedContext filterContext){timer.Stop();filterContext.HttpContext.Response.Write(string.Format("<div>Result elapsed time: {0}</div>", timer.Elapsed.TotalSeconds));}}
}

?

   現在可以將其用在動作方法上了:

     // ProfileAction:演示 ProfileAction 過濾器對于耗時測量的效果
        [ProfileAction]// 對 ProfileAction 動作方法過濾器作為了一個補充
        [ProfileResult]//[CustomAction]public string FilterTest(){return "This is the ActionFilterTest action";}
…

???????? 啟動程序,并導航至/Home/FilterTest,查看效果。可以看出結果過濾器的輸出顯示在動作方法產生的結果之后。因為直到結果被適當地處理之后,OnResultExecuted方法才會被MVC框架執行。這與前面的動作過濾器的OnActionExecuted方法不一樣,請注意這一區別。

?

使用內建的動作過濾器和結果過濾器類

   MVC框架包含一個內建的類,可以用來創建動作過濾器和結果過濾器。這個類的名稱為:ActionFilterAttribute,如:?

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

?

   如果使用這個類有個好處就是不需要重寫和實現不打算使用的方法。除此之外,直接實現過濾器接口沒有任何好處。

???????? 作為演示,在Infrastructure文件夾中創建了一個名為的新類:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Infrastructure
{public class ProfileAllAttribute : ActionFilterAttribute {private Stopwatch timer;public override void OnActionExecuting(ActionExecutingContext filterContext){timer = Stopwatch.StartNew();}public override void OnResultExecuted(ResultExecutedContext filterContext){timer.Stop();filterContext.HttpContext.Response.Write(string.Format("<div>Total elapsed time: {0}</div>", timer.Elapsed.TotalSeconds));}}
}

   ActionFilterAttribute過濾器實現了IActionFilter和 IResultFilter接口,這意味著即時未重寫所有的方法,MVC框架也會把派生類作為兩種過濾器的類型來處理。如上述示例僅實現了IActionFilter接口的OnActionExecuting和IResultFilter接口的OnResultExecuted方法,從而能夠繼續描述前面的主題,以測量動作方法所消耗的時間,并將結果作為一個單一的單元進行處理。下面我們就查看一下該如何使用該過濾器:

// ProfileAction:演示 ProfileAction 過濾器對于耗時測量的效果
        [ProfileAction]// 對 ProfileAction 動作方法過濾器作為了一個補充
        [ProfileResult]// 使用內建的動作過濾器和結果過濾器
        [ProfileAll]//[CustomAction]public string FilterTest(){return "This is the ActionFilterTest action";}
…

   現在就可以啟動程序并查看效果了:

?

使用其他過濾器特性

   MVC框架除了前面介紹的過濾器,還有一些高級的過濾功能,這些過濾器更有趣,但用途不廣。下面就來看看這些過濾器吧。

無注解屬性的過濾器

   常見的使用過濾器的方式是運用注解屬性,但還有一種方式——Controller類也實現了IActionFilter、IAuthorizationFilter、IResultFilter和IExceptionFilter接口。它還對前面看到的每一個OnXXX方法提供了空白虛擬實現,因此,我們可以不用使用注解屬性進行標注,而是直接重寫OnXXX方法來實現過濾器功能。下面是一個演示示例:

using Filters.Infrastructure;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Controllers
{public class HomeController : Controller{/// <summary>/// 一個返回字符串值的動作方法,這樣可以使 MVC 繞過 Razor 視圖引擎,直接將字符串值發送給瀏覽器/// (這只是為了簡化,在實際的項目中還是應該使用視圖——這里只關注控制器)/// </summary>/// <returns></returns>//[CustomAuth(false)][Authorize(Users = "adam,steve,jacqui", Roles = "admin")]public string Index(){return "This is the Index action on the Home Controller";}//自定義的異常過濾器//[RangeException]//內建的異常過濾器[HandleError(ExceptionType = typeof(ArgumentOutOfRangeException), View = "RangeError")]public string RangeTest(int id){if (id > 100){return string.Format("The id value is:{0}", id);}else{throw new ArgumentOutOfRangeException("id", id, "");}}//// ProfileAction:演示 ProfileAction 過濾器對于耗時測量的效果//[ProfileAction]//// 對 ProfileAction 動作方法過濾器作為了一個補充//[ProfileResult]//// 使用內建的動作過濾器和結果過濾器//[ProfileAll]//[CustomAction]public string FilterTest(){return "This is the ActionFilterTest action";}private Stopwatch timer;protected override void OnActionExecuting(ActionExecutingContext filterContext){timer = Stopwatch.StartNew();}protected override void OnResultExecuted(ResultExecutedContext filterContext){timer.Stop();filterContext.HttpContext.Response.Write(string.Format("<div>Total elapsed time: {0}</div>", timer.Elapsed.TotalSeconds));}
}
}

   上面示例中刪除了FilterTest動作方法上的過濾器(已經注釋的部分),因為下面實現的(重寫的)動作方法已經實現了這些功能。下面看看效果(導航地址:/Home/RangeTest/200,該URL的目標是RangeTest動作,但它不會發生在演示HandleError過濾器時可能出現的那種異常):

?

   當要創建一個基類,以派生項目中多個控制器時,這項技術是最有用的。整個過濾點是在一個可重用的位置,放置整個應用程序需要的代碼(還有一種方式是使用全局過濾器)。

注:建議使用注解屬性,這樣可以將控制器邏輯與過濾器邏輯進行分離。如果需要將一個過濾器運用于所有控制器,可以使用全局過濾器。

全局過濾器

   全局過濾器(Global filter)被用于應用程序的所有動作方法。通過App_Start/ FilterConfig.cs文件中定義的RegisterGlobalFilters方法,可以讓一個常規過濾器成為一個全局過濾器。下面示例代碼演示了如何把前面創建的ProfileAll過濾器改成一個全局過濾器:

using Filters.Infrastructure;
using System.Web;
using System.Web.Mvc;namespace Filters
{public class FilterConfig{public static void RegisterGlobalFilters(GlobalFilterCollection filters){filters.Add(new HandleErrorAttribute()); filters.Add(new ProfileAllAttribute());
        }}
}

   上述示例代碼中第一條語句是MVC框架默認創建的異常處理策略,但這一策略默認是禁用的,后面在講解“創建異常過濾器”時將描述該如何啟用這一異常處理策略。

???????? 在注冊全局過濾器時要注意的是過濾器必須為全名(如:filters.Add(new ProfileAllAttribute());)。一旦注冊為全局過濾器,它將被運用于每個動作方法。為了演示這一效果,我們來創建一個新控制器Customer:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Controllers
{public class CustomerController : Controller{public string Index(){return "This is the Customer controller";}}
}

???????? 啟動并導航至/Customer將看到如下效果(即時未在控制器上直接運用過濾器,全局過濾器也會起作用):

?

對過濾器執的行進行排序

   過濾器的執行順序:授權過濾器→動作過濾器→結果過濾器。如果有未處理異常,在任何一階段都會執行異常過濾器。然而,在每一種類型中,都可以控制過濾器的使用順序。

   后面使用一個簡單的動作過濾器類來演示對過濾器的執行進行排序,示例過濾器SimpleMessageAttribute如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Infrastructure
{[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]public class SimpleMessageAttribute : FilterAttribute, IActionFilter{public string Message { get; set; }public void OnActionExecuted(ActionExecutedContext filterContext){filterContext.HttpContext.Response.Write(string.Format("<div>[Before Action: {0}]</div>", Message));}public void OnActionExecuting(ActionExecutingContext filterContext){filterContext.HttpContext.Response.Write(string.Format("<div>[After Action: {0}]</div>", Message));}}
}

   可以將該過濾器的多個實例可以運用于一個動作方法(注意AllowMultiple已被設置為true,所以可以實現這一功能):

using Filters.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Controllers
{public class CustomerController : Controller{[SimpleMessage(Message = "A")][SimpleMessage(Message = "B")]public string Index(){return "This is the Customer controller";}}
}

   下面是這一過濾器的運行效果(/Customer):

?

   在該示例運行時,MVC框架在B過濾器在B過濾器之前執行A過濾器,但也可以按另一種方式執行。MVC框架不會保證任何特定的順序或執行過程。大多數情況下,執行順序是無關緊要的。但當有必要時,可以使用Order屬性進行設置:

…[SimpleMessage(Message = "A", Order = 2)][SimpleMessage(Message = "B", Order = 1)]public string Index(){return "This is the Customer controller";}
…

   Order參數為一個int值,MVC框架以升序方式執行這些過濾器。比如示例中的給B指定了一個最小的值,所以將首先執行B過濾器,如圖:

?

注:OnActionExecuting方法是按指定順序執行的,但OnActionExecuted方法卻以相反的順序執行。在動作方法之前,MVC框架執行過濾器時會建立一個過濾器堆棧,并在隨后釋放這個堆棧。這種釋放行為是不可改變的。

???????? 如果不指定Order值,將會為其設置一個-1的默認值。含義為:如果把有Order值和沒有Order的過濾器混在一起,那些沒有值的過濾器將優先執行,因為它們的Order值最低。

???????? 如果同類型的多個過濾器(如動作過濾器)具有相同的Order值(比如“1”),那么MVC框架會基于過濾器被運用的位置來決定順序:全局過濾器 > 運用于控制器類的過濾器 > 運用于動作方法的過濾器。

注:異常過濾器的執行順序是倒過來的。如果控制器和動作方法上以同樣的Order值運用異常過濾器,動作方法上的(異常)過濾器將首先被執行。帶有同樣的Order值的全局異常過濾器最后被執行。

使用內建過濾器

   MVC框架提供了一些內建的過濾器,詳見下表:

過濾器

描述

RequireHttps

強迫對動作使用HTTPS協議

OutputCache

緩存一個動作方法的輸出

ValidateInput ? 和

ValidateAntiForgeryToken

與安全性有關的授權過濾器

AsyncTimeout

NoAsyncTimeout

用于異步控制器

ChildActionOnlyAttribute

一個支持Html.Action和Html.RenderAction輔助器方法的過濾器

使用RequireHttps過濾器

   RequireHttps過濾器讓動作強制使用HTTPS協議。它將用戶瀏覽器重定向到同一個動作,但使用“Https://”協議前綴。

   在形成不安全請求時,可以重寫HandleNonHttpsRequest方法,以創建自定義行為。該過濾器僅用于GET請求。如果POST請求以這種方式重定向將丟失表單數據值。

注:使用RequireHttps過濾器會有執行順序的問題,這是因為它是授權過濾器而非動作(授權過濾器→動作過濾器→結果過濾器)。

使用OutputCache過濾器

   該過濾器使要對一個動作方法的輸出進行緩存,以便同樣的內容可以被用于對后續相同URL的請求進行服務。緩存動作輸出可以明顯地改善性能——因為它避免了對一個請求進行處理的大部分耗時活動(如查詢數據庫)。當然它也有缺點,就是對所有請求都產生完全相同的相應,這并不適合于所有動作方法。

   OutputCache使用的是ASP.NET平臺內核的輸出緩存工具,在Web Form應用程序中使用過輸出緩存的人應該知道它的配置選項。

   通過對Cache-Control(緩存控制)報頭發送的值施加影響,OutputCache可以用來控制客戶端緩存。下面是該過濾器可以用來設置的參數:

參數

類型

描述

Duration

int

必須的——指定維持輸出緩存的時間,單位:秒

VaryByParam

String(逗號分隔的列表)

告訴ASP.NET,為每個與這些名稱匹配的Request.QueryString值和Request.Form值的組合使用不同的緩存條目。默認值none意為“不隨查詢字符串或表單值而變”。其他選項是“*”,意為“隨所有查詢字符串和表單值而變”。如果不能指定,則使用默認的none值

VaryByHeader

string(逗號分隔的列表)

告訴ASP.NET,為每個在這些HTTP報頭名稱中發送的組合值使用不同的緩存條目

VaryByCustom

string

如果指定,ASP.NET調用Global.asax中的GetVaryByCustomString方法,以這個任意字符串值作為參數進行傳遞,這樣可以生成自已的緩存鍵值。根據瀏覽器名稱及其主要的版本數據,特定值的瀏覽器會使用不同的緩存

VaryByContentEncoding

string(逗號分隔的列表)

允許ASP.NET對每個內容編碼(如gzip、deflate等文件壓縮的編碼格式)創建獨立的緩存條目,這種內容編碼可能是瀏覽器請求的

Location

OutputCacheLocation

指定在哪兒進行輸出緩存。它是一個枚舉值,Server(只在服務器的內存中)、Client(只在客戶端瀏覽器中)、DownStram(在客戶端瀏覽器,或任何HTTP緩存的中間設備中,如一個proxy服務器)、ServerAndClient(Server和Client的組合)、Any(Server和DownSrteam組合)或None(不緩存)。如果不指定,默認值為Any

NoStore

bool

如果為true,告訴ASP.NET發送一個Cach-Control:no-store(不存儲)報頭給瀏覽器,指定該瀏覽器緩存頁面的時間不要長于顯示它的時間。它只用于保護十分敏感的數據

CacheProfile

string

如果指定,只是ASP.NET獲取Web.config中名為“<outputCacheSettings>”的特定小節的緩存設置

SqlDependency

string

如果指定了“數據庫/表名”對,在底層數據庫數據變化時,緩存數據將自動過期。這需要ASP.NET SQL的緩存依賴特性,它的設置比較復雜。進一步細節可以參閱http://msdn.microsoft.com/en-us/library/ms178604.aspx

?

   OutputCache的一個很好的特性是可以把它用于子動作。子動作是在視圖中通過Html.Action輔助器方法來調用的。它能夠在緩存的響應和動態生成的內容之間進行選擇。下面的SelectiveCache控制器做了一個簡單的演示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;namespace Filters.Controllers
{public class SelectiveCacheController : Controller{public ActionResult Index(){Response.Write("Action method is running: " + DateTime.Now);return View();}[OutputCache(Duration = 30)]public ActionResult ChildAction(){Response.Write("Child action method is running: " + DateTime.Now);return View();}}
}

???????? 上面代碼中定義了以下兩種動作方法:

  • ChildAction方法運用了OutputCache過濾器。這是講視圖中調用的動作方法。
  • Index方法是父動作。

   兩個動作方法都把它們的執行時間寫到了Response對象。下面是Index.cshtml視圖,它與Index動作方法相關聯:

@{ViewBag.Title = "Index";
}<h2>This is the main action view</h2>@Html.Action("ChildAction")

   然后就是Index.cshtml視圖調用的ChildAction.cshtml子視圖:

@{Layout = null;
}<h4>This is the child action view</h4>

   啟動并導航至/SelectiveCache。第一次看到父動作和子動作在它們的響應消息中都報告了相同的時間,如果刷新頁面(或用不同的瀏覽器導航到同樣的URL)將看到父動作報告時間變了,但子動作報告的時間保持不變。這說明,后面看到的是原先請求的緩存輸出,如圖:

?

?

提示:在緩存開始之前,可能要對頁面做一次額外的刷新——這是視圖的一個方面。即,當一個MVC框架應用程序第一次啟動時,會對視圖進行編譯。

轉載于:https://www.cnblogs.com/KeSaga/p/5552212.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372886.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372886.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372886.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android_項目文件結構目錄分析

android項目文件結構目錄分析 在此我們新建了一個helloworld的項目&#xff0c;先看一些目錄結構&#xff1a; 這么多的文件夾和文件中&#xff0c;我們重點關注是res目錄、src目錄、AndroidManifest.xml文件&#xff1a; 一、res目錄主要是用來存放android項目的各種資源文件&…

實體 聯系 模型mysql_數據庫系統概念讀書筆記――實體-聯系模型_MySQL

bitsCN.com數據庫系統概念讀書筆記——實體-聯系模型前言為了重新回顧我寫的消息系統架構&#xff0c;我需要重新讀一下數據庫系統概念的前三章&#xff0c;這里簡單的做一個筆記&#xff0c;方便自己回顧基本概念實體-聯系(E-R)數據模型基于對現實世界的這樣一種認識&#xff…

使用Twitter Bootstrap,WebSocket,Akka和OpenLayers玩(2.0)

原始帖子可以在ekito網站上找到。 對于我們的一位客戶&#xff0c;我們需要顯示一張具有實時更新的車輛位置的地圖。 因此&#xff0c;我開始使用Play制作原型&#xff01; 框架及其最新發布的版本2.0&#xff0c;使用Java API。 我從Play的網絡聊天室開始&#xff01; 2.0個樣…

同步時間

同步時間 [rootlocalhost 03]# ntpdate 0.centos.pool.ntp.org 轉載于:https://www.cnblogs.com/cglWorkBook/p/5556920.html

mysql 5.6.23免安裝_mysql5.6.23免安裝配置

1.官網下載&#xff0c;并解壓2.環境變量&#xff0c;path下&#xff0c;追加mysql的bin路徑D:\Program Files\mysql\bin;3.mysql目錄下的my-default.ini重命名為my.ini&#xff0c;并添加下面的代碼basedirD:/Program Files/mysql #mysql路徑datadirD:/Program Files/mysql/d…

在Intellij IDEA中運行Vaadin應用

在本文中&#xff0c;我將向您展示如何使用Intellij IDEA運行vaadin應用程序。 Vaadin提供了一些用于Eclipse和Netbeans的插件。 但是對于Intellij IDEA來說&#xff0c;還沒有插件。 但是部署vaadin應用程序比其他兩個IDE容易。 這是您要遵循的步驟。 1.首先創建一個新項目&am…

mysql主從數據庫

Mysql主從配置&#xff0c;實現讀寫分離 大型網站為了軟解大量的并發訪問&#xff0c;除了在網站實現分布式負載均衡&#xff0c;遠遠不夠。到了數據業務層、數據訪問層&#xff0c;如果還是傳統的數據結構&#xff0c;或者只是單單靠一臺服務器扛&#xff0c;如此多的數據庫連…

安裝openstack時遇到的錯誤

學習opensatck的第一步是安裝DevStack來進行本機操作 1. 下面命令沒有權限&#xff0c;解決辦法&#xff1a;切換到root用戶下執行sudo -s echo "stack ALL(ALL) NOPASSWD: ALL" >> /etc/sudoers2. 執行下面命令提示沒有git&#xff0c;解決辦法&#xff1a;su…

Java EE 6示例– Galleria –第3部分

關于Galleria示例的先前文章&#xff08; 第1 部分 | 第2部分 | 第3部分 | 第4部分 &#xff09;指導您完成基礎知識以及對GlassFish和WebLogic的初始部署。 從今天開始&#xff0c;我嘗試在其中添加一些企業級功能&#xff0c;因為我發現他們在自己的項目中提出了很多要求。 我…

在 Windows 上測試 Redis Cluster的集群填坑筆記

redis 集群實現的原理請參考http://www.tuicool.com/articles/VvIZje集群環境至少需要3個節點。推薦使用6個節點配置&#xff0c;即3個主節點&#xff0c;3個從節點。新建6個文件夾 分別是 7000/7001/7002/7003/7004/7005將redis.windows.conf 復制一份然后修改配置文件中的下面…

不成為編程天才的5種貢獻方式

安迪萊斯特&#xff08;Andy Lester&#xff09;早在三月發布了原始指南&#xff0c;其中介紹了14種不成為編程天才或搖滾明星的貢獻開源的方法 &#xff0c;我真的很喜歡這個想法。 這就是為什么我決定稍微采納一下這篇文章&#xff0c;并告訴您如何以及可以做什么來支持自己喜…

mysql數據庫設計與應用答案智慧樹_智慧樹_MySQL數據庫設計與應用_完整免費答案...

單位工程施工組織設計的技術經濟指標體系包括有()。A&#xff0e;工期指標B&#xff0e;勞動指標C&#xff0e;臺班利用率D&#xff0e;成本降低大跨徑橋梁采用()將會取得良好的技術經濟效益。A&#xff0e;橫移法施工B&#xff0e;頂推法施工C&#xff0e;轉體法施工D&#xf…

拓撲排序最長鏈-P3119 [USACO15JAN]草鑒定Grass Cownoisseur

https://www.luogu.org/problem/show?pid3119 本來我是來練習tarjan的&#xff0c;結果tarjan部分直接copy了&#xff0c;反而拓撲排序部分想了好久&#xff1b; 這道題SZB大神兩次就AC&#xff1b; 但我等到AC&#xff0c;寫好題解就只能洗洗睡了&#xff1b; 唉~ 差距怎…

談談父類和子類的隔離性

以前寫代碼知道要給類外設置訪問接口, 例如下例: 1 class Money2 {3 public:4 Money(int money) : m_curValue(money){}5 6 void store(int money) { m_curValue money;}7 void spent(int money){ m_curValue - money;}8 private:9 int m_curValue…

用于數據庫測試的DBUnit,Spring和注釋

如果您曾經嘗試用Java編寫數據庫測試&#xff0c;則可能會碰到DBUnit 。 DBUnit允許您設置和拆除數據庫&#xff0c;以便它包含可針對其編寫測試的一致行。 通常&#xff0c;您可以通過編寫一個簡單的XML文檔來指定要DBUnit插入的行&#xff0c;例如&#xff1a; <?xml ve…

阿里云centos 7.6安裝mysql_阿里云Centos7上安裝MySQL教程

1 基本安裝過程1.查看系統是否安裝了mysql軟件# rpm -qa|grep -i mysql2.將已經安裝過的軟件卸載掉。注意&#xff1a;這樣的卸載是不徹底&#xff0c;不過這里夠用了# yum remove 軟件名3.CentOS 7的yum源中默認是沒有mysql的。所以&#xff0c;為了解決這個問題我們首先下載安…

Struts2中數據封裝方式

一、通過ActionContext類獲取 public class ActionContextDemo extends ActionSupport { Override public String execute() throws Exception { //獲取ActionContext對象 ActionContext context ActionContext.getContext(); //調用getParameters…

第五章、搭建S3C6410開發板的測試環境

通過對本章的學習&#xff0c;我對s3c6410開發板的測試環境有了一定的認識&#xff0c;并掌握了如下的知識點&#xff1a;一、對于s3c6410這款開發板&#xff0c;它是一款低功耗、高性價比的處理器&#xff0c;它是基于ARM11的內核。二、不同開發板的區別主要在燒錄嵌入式系統的…

IBM JVM調整– gencon GC策略

本文將向您詳細介紹從Java虛擬機&#xff08;例如HotSpot或JRockit&#xff09;遷移到IBM JVM時重要的Java堆空間調整注意事項。 該調整建議基于我為我的一個IT客戶端執行的最新故障排除和調整任務。 IBM JVM概述 正如您可能從其他文章中看到的那樣&#xff0c;IBM JVM在某些方…