Asp.Net Mvc 自定義擴展

 

目錄:html

  1. 自定義模型IModelBinder
  2. 自定義模型驗證
  3. 自定義視圖引擎
  4. 自定義Html輔助方法
  5. 自定義Razor輔助方法
  6. 自定義Ajax輔助方法
  7. 自定義控制器擴展
  8. 自定義過濾器
  9. 自定義ActionResult

自定義模型IModelBinderweb

IModelBinder主要解決的問題是,將請求的數據轉換成須要的數據這部分邏輯進行了封裝。好比說 http://localhost:4742/Person/Person/2 請求的參數Id是2,經過參數2,得到2相關的全部數據。ajax

這樣作的好處是:json

  1. 使代碼變得更加簡潔
  2. 幫助咱們獲取HTTP請求中的數據
  3. 幫助咱們完成必要的數據類型轉換

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

經過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);
        }
    }
JObjectActionResult的擴展

控制器中調用輸出:
使用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);
        }
    }
CustomView

調用它,只須要實例化一下就好了。

public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";
            User u = new Models.User();
            return  new CustomView<User>(u);
        }

 

 

 下載地址

你們還有什麼好的擴展方法,能夠回覆該帖哦。

相關文章
相關標籤/搜索