目錄:html
IModelBinder主要解決的問題是,將請求的數據轉換成須要的數據這部分邏輯進行了封裝。好比說 http://localhost:4742/Person/Person/2 請求的參數Id是2,經過參數2,得到2相關的全部數據。ajax
這樣作的好處是:json
Controller部分:瀏覽器
當訪問http://localhost:4742/Person/Person?Name=admin&Age=12時,自動轉換爲setting對象緩存
[HttpPost] public ActionResult Person2([ModelBinder(typeof(SettingsBinder))]Settings settings) { return View("Person"); }
IModelBinder部分服務器
SettingsBinder繼承了IModelBinder,並實現了BindModel,經過controllerContext.HttpContext.Request獲取請求,從請求中獲取參數值,而後轉換爲對象cookie
public class SettingsBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var request = controllerContext.HttpContext.Request; // 從request中獲取參數值 var name = request["Name"]; var age = request["Age"]; // 而後將參數值轉爲對象 var setting = new { Name = name, Age = age }; return setting; } }
注:當Person2([ModelBinder(typeof(SettingsBinder))]Settings settings)已存在時,不能再定義Person2方法app
自定義驗證ide
經過定義自定義驗證特性類,實現View的模型驗證,NotEqualTo即自定義驗證
public class RegisterModel { [Required] [StringLength(6, MinimumLength = 2)] //加 [Display(Name = "用戶名")] public string UserName { get; set; } [NotEqualTo("UserName", ErrorMessage = "不能與用戶名的值相同")] public string OtherName { get; set; } // NotEqualTo 是自定義模型驗證特性 }
NotEqualToAttribute繼承了ValidationAttribute和IClientValidatable ,並實現了IsValid和GetClientValidationRules方法
經過NotEqualTo構造參數的值UserName,得到該對象對應該參數值的屬性值,匹配屬性的值和約束的值OtherName是否相等,而後返回結果信息
using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Web.Mvc; namespace MvcValidation.Extension { // ValidationAttribute 驗證特性 // IClientValidatable 客戶端驗證接口(View視圖驗證) public class NotEqualToAttribute : ValidationAttribute, IClientValidatable { public string OtherProperty { get; set; } // 構造參數 public NotEqualToAttribute(string otherProperty) { OtherProperty = otherProperty; } // 驗證方法 protected override ValidationResult IsValid(object value, ValidationContext validationContext) { //從驗證上下文中能夠獲取咱們想要的的屬性 var property = validationContext.ObjectType.GetProperty(OtherProperty); if (property == null) { return new ValidationResult(string.Format(CultureInfo.CurrentCulture, "{0} 不存在", OtherProperty)); } //獲取屬性的值 var otherValue = property.GetValue(validationContext.ObjectInstance, null); // 判斷並返回驗證結果 if (object.Equals(value, otherValue)) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } return null; } // 客戶端驗證 public System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { // 設置客戶端驗證結果信息 var rule = new ModelClientValidationRule { ValidationType = "notequalto", ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()) }; rule.ValidationParameters["other"] = OtherProperty; yield return rule; } } }
自定義視圖引擎
系統提供了視圖和視圖引擎,咱們須要瞭解它以後繼承並重寫它的邏輯。
/* * 思路 * 一、控制器方法返回ActionResult是一個抽象類 * 二、ActionResult的其中一個子類ViewResult,正是她使用IView實例最終渲染出視圖 * 三、須要自定義IView * 四、IViewEngine管理着IView,同時也須要自定義IViewEngine * 五、自定義IViewEngine是須要全局註冊的 */
//namespace System.Web.Mvc //public interface IView //{ // 第一個參數ViewContext包含了須要被渲染的信息,被傳遞到前臺的強類型Model也包含在其中。 // 第二個參數TextWriter能夠幫助咱們寫出想要的html格式。 // void Render(ViewContext viewContent, TextWriter textWriter); //}
//namespace System.Web.Mvc //public interface IViewEngine //{ // // FindPartialView:在當前控制器上下文ControllerContext中找到部分視圖。 // System.Web.Mvc.ViewEngineResult FindPartialView(System.Web.Mvc.ControllerContext controllerContext, string partialViewName, bool useCache); // // FindView:在當前控制器上下文ControllerContext中找到視圖。 // System.Web.Mvc.ViewEngineResult FindView(System.Web.Mvc.ControllerContext controllerContext, string viewName, string masterName, bool useCache); // // ReleaseView:釋放當前控制器上下文ControllerContext中的視圖。 // void ReleaseView(System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.IView view); //}
咱們將派生出它們的類,經過自定義視圖引擎類實現渲染,並顯示。
準備資源:
public class Student { public int Id { get; set; } public string Name { get; set; } public int Score { get; set; } } public class DataAccess { List<Student> students = new List<Student>(); public DataAccess() { for (int i = 0; i < 10; i++) { students.Add(new Student() { Id=i+1, Name="Name"+Convert.ToString(i+1), Score = i+80 }); } } public List<Student> GetStudents() { return students; } }
自定義擴展
public class StudentView : IView { /// <summary> /// 渲染 /// 經過得到視圖上下文數據,而後自定義輸出格式經過TextWriter輸出數據 /// </summary> /// <param name="viewContent"></param> /// <param name="writer"></param> public void Render(ViewContext viewContent, TextWriter writer) { // 從視圖上下文ViewContext拿到model var model = viewContent.ViewData.Model; var students=model as List<Student>; // 自定義輸出視圖的html格式 writer.Write("<table border=1><tr><th>編號</th><th>名稱</th><th>分數</th></tr>"); foreach (Student stu in students) { writer.Write("<tr><td>" + stu.Id + "</td><td>" + stu.Name + "</td><td>" + stu.Score + "</td></tr>"); } writer.Write("</table>"); } } public class StudentViewEngine : IViewEngine { //呈現部分視圖 public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) { throw new NotImplementedException(); } //呈現視圖 public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) { if (viewName == "StudentView") { // 呈現自定義視圖 return new ViewEngineResult(new StudentView(), this); } else { return new ViewEngineResult(new string[] { "針對Student的視圖還沒建立!" }); } } //顯示視圖 public void ReleaseView(ControllerContext controllerContext, System.Web.Mvc.IView view) { } }
至此自定義視圖引擎完成。接下來咱們進行調用:
咱們只須要在View中指定自定義視圖的名稱便可。
public ActionResult Index() { var students = new DataAccess().GetStudents(); ViewData.Model = students; return View("StudentView"); }
設置默認的,全局的視圖引擎
只須要添加ViewEngines.Engines.Add(new StudentViewEngine());便可實現。
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); ViewEngines.Engines.Add(new StudentViewEngine()); }
自定義HtmlHelper輔助方法
定義擴展方法類和擴展方法
using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; // 設置命名空間爲統一的Html命名空間 namespace System.Web.WebPages.Html { // 設置靜態類 public static class HtmlExtensions { // 爲HtmlHelper類提輔助方法Img,參數爲src和alt public static MvcHtmlString Img(this HtmlHelper html,string src,string alt)
{
return MvcHtmlString.Create("<img src=\"" + src + "\" alt=\"" + alt + "\" />");
} } }
在View頁面中調用該擴展方法
@* 調用Img方法,前者爲src,後者爲alt,生成的結果是:<img src="C:\images\btn.ico\" alt="" /> *@ @Html.Img("C:\\images\\btn.ico","")
自定義Razor輔助方法
在MVC項目根目錄下新建一個文件夾名爲:App_Code,用於存放MyHelpers.cshtml
編寫MyHelpers.cshtml內容以下:
至關於定義了MyHelpers.li(List<string> arrays)方法,經過關鍵字helper進行聲明,這樣其餘的cshtml頁面均可以訪問該方法
@helper li(List<string> arrays) { <ul> @foreach (var item in arrays) { <li>@(item)</li> } </ul> }
cshtml頁面訪問li方法
Index.cshtml頁面調用:
@MyHelpers.li(new List<string>() { "甲","乙","丙","丁"})
頁面輸出結果:
自定義AjaxHelper輔助方法
與HtmlHelper擴展同樣,爲AjaxHelper擴展一個方法Textbox,並設置相應的屬性
public static class HtmlExtensions { // 爲HtmlHelper類提輔助方法Img,參數爲src和alt public static MvcHtmlString Img(this HtmlHelper html, string src, string alt) { return MvcHtmlString.Create("<img src=\"" + src + "\" alt=\"" + alt + "\" />"); } public static MvcHtmlString Textbox(this AjaxHelper ajaxHelper, string name, AjaxOptions ajaxOptions, object htmlAttributes) { // 設置標籤名 var tag = new TagBuilder("input"); // 設置屬性值 tag.MergeAttribute("name", name); tag.MergeAttribute("type", "text"); tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); tag.MergeAttributes((ajaxOptions ?? new AjaxOptions()).ToUnobtrusiveHtmlAttributes()); tag.MergeAttribute("value", "自定義Ajax擴展"); // 輸出Html return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal)); } }
View調用:
@Ajax.Textbox("search", new AjaxOptions { Url = @Url.Action("GetTime"), UpdateTargetId = "divTime", InsertionMode = InsertionMode.Replace }, new { size = 50 })
輸出結果:
輸出結果的源碼:
<input data-ajax="true" data-ajax-mode="replace" data-ajax-update="#divTime" data-ajax-url="/AjaxHelperExt/GetTime" name="search" size="50" type="text" value="自定義Ajax擴展"></input>
自定義UrlHelper輔助方法
略.
自定義控制器擴展BaseController
// BaseController 針對Controller進行重寫 // 而且提供了一些公用的方法如權限校驗,Action跳轉、日誌記錄等 public class BaseController : Controller { protected override void OnException(ExceptionContext filterContext) { // 處理異常 base.OnException(filterContext); } protected override void Initialize(RequestContext requestContext) { // 處理初始化信息,如Cookie,Session等緩存信息 base.Initialize(requestContext); } protected override void OnActionExecuting(ActionExecutingContext filterContext) { // 在調用操做方法前調用 base.OnActionExecuting(filterContext); } protected override void OnActionExecuted(ActionExecutedContext filterContext) { // 在調用操做方法後調用 base.OnActionExecuted(filterContext); } }
自定義過濾器
路由訪問過濾器
/// <summary> /// 路由訪問過濾器 /// </summary> public class SystemIActionFilter : IActionFilter { // // Summary: // Called after the action method is invoked. // 在Action返回以後 // Parameters: // filterContext: // Information about the current request and action. public void OnActionExecuted(ActionExecutedContext filterContext) { } // // Summary: // Called before the action method is invoked. // 在進入Action以前 // 說明:使用RedirectToRouteResult進行路由值進行重定向時 // RouteName 路由名稱 // RouteValues 路由值 特別注意第三個值 Permanent 獲取一個值 // 該值指示重定向是否應爲永久重定向 若是爲true 在本程序會出現問題 // Parameters: // filterContext: // Information about the current request and action. public void OnActionExecuting(ActionExecutingContext filterContext) { //驗證 控制器 視圖 string tempAction = filterContext.RouteData.Values["action"].ToString(); string tempController = filterContext.RouteData.Values["controller"].ToString(); string tempLoginAction = filterContext.RouteData.Values["action"].ToString(); if (tempAction == "HomeLogin" && tempController == "Home" || tempLoginAction == "UserLogin" ? false : true) { //請求登陸時 if (tempAction == "UserLogin" && tempController == "Home" ? false : true) { //Cookie HttpCookie tempToken = filterContext.HttpContext.Request.Cookies["exclusiveuser_token"]; if (tempToken == null) { filterContext.Result = new RedirectToRouteResult("HomeLogin", new RouteValueDictionary(new { controller = "Home", action = "HomeLogin" }), false); } //登陸token不爲null時 進行合法性驗證token 頭部,載荷,簽名,cookie過時時間 if (tempToken == null ? false : true) { //UserToken 方法 將驗證 token 合法性 包括token 簽名 ,token載荷,cookie 過時時間等 //string SystemToken = new SecondTrackToken().UserToken(); //if (SystemToken == null) //{ // filterContext.Result = new RedirectToRouteResult("HomeLogin", new RouteValueDictionary(new { controller = "Home", action = "HomeLogin" }), false); //}; } } } } }
異常處理過濾器
/// <summary> /// 異常處理過濾器 /// </summary> public class SystemIExceptionFilter : IExceptionFilter { void IExceptionFilter.OnException(ExceptionContext filterContext) { Exception exception = filterContext.Exception; if (filterContext.ExceptionHandled) { return; } HttpException http = new HttpException(null, exception); /* * filterContext.Exception.Message 錯誤信息 */ string messager = filterContext.Exception.Message; /* * 錯誤日誌 */ //Log4NetHelp help = new Log4NetHelp(); //help.ErrorString(filterContext.Exception.Message); /* * 設置自定義異常已經處理,避免其餘過濾器異常覆蓋 */ filterContext.ExceptionHandled = true; /* * 在派生類重寫時,設置或者重寫一個值該值指定是否禁用ISS7.0中自定義錯誤 */ filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; } }
受權處理(獲取客戶端信息)
public class SystemIAuthorizationFilter : IAuthorizationFilter { void IAuthorizationFilter.OnAuthorization(AuthorizationContext filterContext) { //當前操做計算機用戶 string pcName = ((System.Web.HttpServerUtilityWrapper)((System.Web.HttpContextWrapper)filterContext.RequestContext.HttpContext).Server).MachineName; //視圖 string action = ((System.Web.Mvc.ReflectedActionDescriptor)filterContext.ActionDescriptor).ActionName; //控制器 string controller = ((System.Web.Mvc.ReflectedActionDescriptor)filterContext.ActionDescriptor).ControllerDescriptor.ControllerName; //請求時間 string time = filterContext.RequestContext.HttpContext.Timestamp.ToString(); //請求相對路徑 string absturl = ((System.Web.UnvalidatedRequestValuesWrapper)((System.Web.HttpRequestWrapper)((System.Web.HttpContextWrapper)filterContext.RequestContext.HttpContext).Request).Unvalidated).Url.AbsoluteUri; //狀態 string code = ((System.Web.HttpResponseWrapper)((System.Web.HttpContextWrapper)filterContext.RequestContext.HttpContext).Response).Status; // 瀏覽器版本 string browser = ((System.Web.HttpBrowserCapabilitiesWrapper)((System.Web.HttpRequestWrapper)((System.Web.HttpContextWrapper)filterContext.RequestContext.HttpContext).Request).Browser).Type; //請求方式 string gepPost = ((System.Web.HttpRequestWrapper)((System.Web.Mvc.Controller)filterContext.Controller).Request).RequestType; //本地主機名稱解析DNS自己處理。 string server = ((System.Web.HttpRequestWrapper)((System.Web.HttpContextWrapper)filterContext.HttpContext).Request).UserHostAddress; #region server 說明 /* * 版權(c)1993 - 2009微軟(msft . o:行情)。 * * 這是一個示例所使用的主機文件微軟爲Windows TCP / IP。 * * 這個文件包含IP地址到主機名的映射。 每個 * 條目應該保存在單個行。 IP地址應 *被放置在第一列對應的主機名。 *的IP地址和主機名應該由至少一個 *空間。 * *此外,評論(這樣的)多是插入的我的 *線或後機器名稱用「*」符號。 * 例如: * * 102.54.94.97 rhino.acme.com源服務器 * 38.25.63.10 x.acme.com x客戶機主機 *本地主機名稱解析DNS自己處理。 * 127.0.0.1 localhost *::1 localhost */ #endregion //用戶 //部門 //職位 } }
自定義屬性過濾器
public class CheckLogin: ActionFilterAttribute { public override void OnResultExecuting(ResultExecutingContext filterContext) { HttpCookieCollection CookieCollect = System.Web.HttpContext.Current.Request.Cookies; if (CookieCollect["username"] == null || CookieCollect["password"] == null) { filterContext.Result = new RedirectResult("/Home/Login"); } else { if (CookieCollect["username"].Value != "admin" && CookieCollect["password"].Value != "123456") { filterContext.Result = new RedirectResult("/Home/Login"); } } } }
過濾器定義好後,須要在過濾器配置類FilterConfig中添加
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); //將自定義異常過濾器的優先級提升,防止異常被默認的HandleError處理(也能夠自定義類重寫HandleErrorAttribute 實現錯誤處理) filters.Add(new SystemIExceptionFilter(), 1); //控制器過濾器 filters.Add(new SystemIActionFilter(), 2); //受權過濾器 filters.Add(new SystemIAuthorizationFilter(), 3);
// 自定義屬性過濾器
filters.Add(new CheckLogin()); } }
自定義屬性過濾器在控制器中調用:
在方法的上面加上特性:CheckLogin,當調用該方法時會先進行過濾再執行下面的邏輯。
[CheckLogin] public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); }
自定義ActionResult
擴展的ActionResult,繼承自ActionResult,須要重寫ExecuteResult方法,經過構造函數傳入參數值,
使用ExecuteResult方法的ControllerContext上下文得到HttpResponse,HttpResponse使用輸出參數值結果。
/// <summary> /// 自定義JObject返回結果 /// </summary> public class JObjectActionResult : ActionResult { /// <summary> /// 結果集 /// </summary> public JObject JObject { get; set; } public Encoding ContentEncoding { get; set; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } HttpResponseBase response = context.HttpContext.Response; response.ContentType = "application/json"; if (ContentEncoding != null) { response.ContentEncoding = ContentEncoding; } if (JObject != null) { response.Write(JObject.ToString()); } } }
經過response.Write(JObject.ToString());最後輸出結果。
接下來咱們看看調用:
public ActionResult Index() { return View(); }
默認的View()是Controller.View()的方法,所以咱們爲Controller類擴展一個方法。定義擴展內容以下:
public static class JObjectActionResultExtensions { public static JObjectActionResult JObjectResult(this Controller controller, JObject obj) { return new JObjectActionResult { JObject = obj }; } public static JObjectActionResult JObjectResult(this Controller controller, bool success) { JObject obj = new JObject(); obj.Add("success", success); if (success) { obj.Add("code", 200); obj.Add("msg", "Success!"); } else { obj.Add("code", 500); obj.Add("msg", "Error!"); } return JObjectResult(controller, obj); } public static JObjectActionResult JObjectResult(this Controller controller, bool success, int code, string msg) { JObject obj = new JObject(); obj.Add("success", success); obj.Add("code", code); obj.Add("msg", msg); return JObjectResult(controller, obj); } }
控制器中調用輸出:
使用this關鍵字調用JObjectResult便可輸出結果。
public ActionResult About() { ViewBag.Message = "Your application description page."; return this.JObjectResult(true); }
接下來咱們再擴展一個序列化的Result.
/// <summary> /// 泛型的序列化結果 /// </summary> /// <typeparam name="TData"></typeparam> public class CustomView<TData> : ActionResult where TData:class,new() { /// <summary> /// 構造函數傳入參數 /// </summary> /// <param name="t"></param> public CustomView(TData t) { data = t; } public TData data; protected JsonSerializerSettings SerializerSettings; protected void InitSerialization(ControllerContext context) { HttpResponseBase response = context.HttpContext.Response; response.ContentType = "text/html"; if (SerializerSettings == null) { SetSerializerSettings(); } response.Write(JsonConvert.SerializeObject(data, Formatting.None, SerializerSettings)); } protected virtual void SetSerializerSettings() { SerializerSettings = new JsonSerializerSettings { Converters = new List<JsonConverter> { new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd hh:mm" } } }; } public override void ExecuteResult(ControllerContext context) { InitSerialization(context); } }
調用它,只須要實例化一下就好了。
public ActionResult Contact() { ViewBag.Message = "Your contact page."; User u = new Models.User(); return new CustomView<User>(u); }
你們還有什麼好的擴展方法,能夠回覆該帖哦。