demoshop

demo, trying to be the best_

MVC的內建驗證中有一個非常好用的 Remote ,如果各位開發人員有用過 jQuery.validate 應該對於 Remote 驗證不會陌生,簡單一點的解釋就是它可以將「後端驗證」做的很像「前端驗證」利用這種方式,開發人員不再受限於前端驗證可以判斷的資訊太少,讓驗證寫的不夠精準的問題,雖然 Remote 驗證相當好用但是有一點小地雷還是要知道的。

demo廢言之前 demo 就在 twMVC 和微軟講 ASP.NET MVC 驗證的課程時有提到解決方式,但上次 twMVC 固定聚會時有朋友問到,讓我驚覺我還沒寫成文章.....所以立刻來補上。

 

demo已經介紹過許許多多的 MVC 驗證技巧文章,每個內建驗證都是同時支援前端與後端驗證的,用了一陣子後這個觀念很自然的植入開發人員的腦中,但是偏偏 Remote 不是那麼一回事,Remote 只支援前端驗證是很多開發人員不知道的事情,就這樣很開心的用了這強大的 Remote 後發現前端 JS 被關掉以後怎麼就什麼都擋不住了,雖然這是設計理念的原因不算是一個 Bug 但是這造成了開發時的思考會卡住的問題,變得還要記憶 Remote 不支援後端驗證,這十分的討厭,所以我們應該要來把它改成支援後端驗證因為沒有什麼特別之處(反射算特別嗎?)所以以下ˋ就直接貼出完整 Code

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace demoValidation
{
    public class RemoteDoublePlus : RemoteAttribute
    {
        private string action { get; set; }
        private string controller { get; set; }
        private string area { get; set; }



        public RemoteDoublePlus(string action, string controller, string area)
            : base(action, controller, area)
        {
            this.action = action;
            this.controller = controller;
            this.area = area;
            
            //修正 Remote 驗證遇到根 Area 的問題
            //http://demo.tc/Post/756
            this.RouteData["area"] = area;
        }

        //覆寫 IsValid 方法 實作後端驗證
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var additionalFields = this.AdditionalFields.Split(',');
            var propValues = new List<object>();
            propValues.Add(value);
            foreach (string additionalField in additionalFields)
            {
                var prop = validationContext.ObjectType.GetProperty(additionalField);
                if (prop != null)
                {
                    object propValue = prop.GetValue(validationContext.ObjectInstance, null);
                    propValues.Add(propValue);
                }
            }

            var controllerType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(d => d.Name.ToLower() == (this.controller + "Controller").ToLower());
            if (controllerType != null)
            {
                var instance = Activator.CreateInstance(controllerType);

                var method = controllerType.GetMethod(this.action);

                if (method != null)
                {
                    ActionResult response = (ActionResult)method.Invoke(instance, propValues.ToArray());

                    if (response is JsonResult)
                    {
                        bool isAvailable = false;
                        JsonResult json = (JsonResult)response;
                        string jsonData = Convert.ToString(json.Data);

                        bool.TryParse(jsonData, out isAvailable);

                        if (!isAvailable)
                        {
                            return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
                        }
                    }
                }
            }
            return null;
        }
    }
}

 

分隔線

回應討論