demoshop

demo, trying to be the best_

demo 在【ASP.NET MVC3 如何使用內建驗證功能達到前端與後端的同時驗證】有介紹過 Remote 驗證這種大絕形式的前端驗證使用方式,但是如果你的 MVC 專案有用到 Area 機制,那你很可能會發現爆炸了,這篇文章就簡單的介紹一下怎麼處理掉這塊事情。

.●立刻簡單回顧一下 Remote 驗證的方式,使用 ASP.NET MVC3 的模版來改造一下

開啟 \Models\AccountModels.cs

public class LogOnModel
    {
        [Required]
        [Display(Name = "User name")]
        [Remote("CheckUserName", "Validate", ErrorMessage = "遠端驗證失敗")]
        public string UserName { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [Display(Name = "Remember me?")]
        public bool RememberMe { get; set; }
    }

●建立一個驗證專用的 Controller (一般來說我會建議各位將 Remote 驗證專用的 Controller 統一起來)

建立 ValidateController.cs

namespace MvcApplication1.Controllers
{
    public class ValidateController : Controller
    {
        public JsonResult CheckUserName(string userName)
        {
            bool isValidate = false;

            if (Url.IsLocalUrl(Request.Url.AbsoluteUri))
            {
                //利用 IsLocalUrl檢查是否為網站呼叫的
                //借此忽略一些不必要的流量

                if (userName != "demoshop")
                {
                    //因連資料庫麻煩
                    //所以假裝示範不可以註冊某一名字
                    isValidate = true;
                }
            }
            // Remote 驗證是使用 Get 因此要開放
            return Json(isValidate, JsonRequestBehavior.AllowGet);
        }
    }
}

●馬上來到登入畫面就可以看到驗證效果了


demo廢言以上是快速的複習,用起來是相當的簡單方便,但是當你的 MVC 架構開始大了起來需要使用 Area 機制的時候就會發現為什麼遠端驗證的功能不正常,再來模擬一個 名稱為 Test 的 Area 要呼叫相同的遠端驗證邏輯來看看。

建立完成的 Test 如下圖:

  • Controller 就是 Default1Controller 內容是空的,我什麼都沒放。
  • 依據 Controller 預設的 Index action 建立出對應的 View,View 的 ViewModel 使用了和 LogOn.cshtml 一樣的 ,完整 HTML 如下。
@model MvcApplication1.Models.LogOnModel

@{
    ViewBag.Title = "Log On";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>我是仿的</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.")

@using (Html.BeginForm()) {
    <div>
        <fieldset>
            <legend>Account Information</legend>

            <div class="editor-label">
                @Html.LabelFor(m => m.UserName)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(m => m.UserName)
                @Html.ValidationMessageFor(m => m.UserName)
            </div>

            <div class="editor-label">
                @Html.LabelFor(m => m.Password)
            </div>
            <div class="editor-field">
                @Html.PasswordFor(m => m.Password)
                @Html.ValidationMessageFor(m => m.Password)
            </div>

            <div class="editor-label">
                @Html.CheckBoxFor(m => m.RememberMe)
                @Html.LabelFor(m => m.RememberMe)
            </div>

            <p>
                <input type="submit" value="Log On" />
            </p>
        </fieldset>
    </div>
}

●重複作業完成後進入頁面(記得先 Build)馬上再輸入 demoshop 卻發現了錯誤

看圖說故事,我們的遠端驗證位置不是放在 Area 內,但是看得出來他去 Call 的網址包含了 Area name 所以很自然的找不到,而發生了 404 ,這時候你或許會馬上修改成這樣

自己明確的告訴他 Area 是空的


demo廢言編譯後再來測試,你會發現結果是一樣的...........

經過一番輾轉難眠就反組譯了ASP.NET MVC 3原本的 Code 來看看

注意事項看到特別框起來的地方了嗎?被濾掉了.....,還有其實不用反組譯,因為  ASP.NET MVC 是 Open Source 的【線上直接看


●既然知道了原因如此單純,那就動手改 Code 吧,建立一個新的 Class

public class RemotePlus : RemoteAttribute
    {
        public RemotePlus(string action, string controller, string area)
            : base(action, controller, area)
        {
            this.RouteData["area"] = area;
        }
    }

●把 Area 確實的傳過去,再把 Medadata 的部份改用新寫的這個

       [Required]
        [Display(Name = "User name")]
        //[Remote("CheckUserName", "Validate", "", ErrorMessage = "遠端驗證失敗")]
        [RemotePlus("CheckUserName", "Validate", "", ErrorMessage = "新遠端驗證失敗")]
        public string UserName { get; set; }

●這次再測試就會正常拉(記得編譯....

 

demo廢言寫完這篇以後跑去看了一下目前 ASP.NET MVC 4 Beta 的版本依然是沒有改變,可能有什麼考量在吧

(感謝小朱提供我 MVC 4 的 dll)

回應討論