回顧
《前端基於easyui的mvc擴展》、《前端基於easyui的mvc擴展(續)》前兩篇介紹了mvc內如何基於easyui進行擴展,在mvc里面有很多簡化的語法可以讓開發人員快速開發,既然我們已經對mvc進行了擴展,那么當然也不能漏掉了基礎的web form了。首先我們來比較一下mvc和web form,如果前端不使用razor,都是用aspx頁面的話,使用的語法是一樣的,只是mvc內提供了HtmlHelper、Model、ViewData等來簡化開發。
也就是說,如果我們使用如下的方式,其實在web form里面也是可行的,但是與mvc不同的是,web form內並沒有像HtmlHelper的對象可以直接進行擴展,因此我們只能重新創建一個類來實現這些功能,既然無法使用類似HtmlHelper的對象擴展,那么model對象也就必須在編碼標簽的時候手動傳入了,大致代碼如下:
<% User user = new User { Name = "測試", StateId = 2 }; %>
<%=EasyUIHelper.ValidateText(u => u.Name, user)%>
<%=EasyUIHelper.Datebox(u => u.Name, user)%>
<%=EasyUIHelper.Combobox<User>(u => u.StateId, user, "States", "{ id: 'myCob', 'data-options': 'width: 100, editable: false' }")%>
實現
那么要達到以上的效果其實也不難,因為我們在前兩篇已經進行了實現了,只要將其重構一下,使其可以支持在web form內工作便可以了,那么首先我們遇到的問題便是如何把表達式樹轉化為屬性,這個主題我在《獲取Lambda表達式內表達式的值》該文章中已經進行了講解,調整后代碼大致如下:
public static string ValidateText<TModel>(Expression<Func<TModel, object>> expression, TModel model, string attributeJson, Dictionary<string, string> attributes)
{
string propertyName = PropertyHelper.ResloveName(expression);//關於獲取表達式值的文章
PropertyInfo property = typeof(TModel).GetProperty(propertyName);
TagBuilder tag = new TagBuilder("input");
//增加name、type屬性
ValidationAttribute[] validationAttrs;
if (property.TryGetAttributes(out validationAttrs))
{
//請閱讀轉換規則代碼
}
var extraAttributes = string.IsNullOrEmpty(attributeJson) ? attributes : JsonHelper.Deserialize<IDictionary<string, string>>(attributeJson);//基於Newtonsoft轉化json的公用方法
//添加屬性
return tag.ToString();
}
這樣前端的代碼就順利轉換完成了,剩下的便是如何讓表單提交到服務端后,怎么樣進行驗證呢,大概的流程如下:
- 將提交到服務端的表單直接轉化為對應的實體類
- 讀取實體類各個屬性以及屬性內的驗證特性,一一進行進行驗證
- 如果中間沒有驗證失敗的話,那么就說明實體是符合驗證要求的,可進行其他操作
第一步其實就是利用反射將屬性相對應的值一一賦值給相應的屬性而已,這里我們就不重復去實現了。
獲取屬性驗證特性,我們可以通過擴展MemberInfo(因為PropertyInfo和MethodInfo都是MemberInfo的派生類)來獲取特性,大致代碼如下:
public static bool TryGetAttributes(this MemberInfo member, out TAttribute[] attributes, bool inherit = false) where TAttribute : Attribute
{
attributes = null;
var objs = member.GetCustomAttributes(typeof(TAttribute), inherit);
if (objs.Length == 0)
return false;
attributes = Array.ConvertAll(objs, obj => obj as TAttribute);
return true;
}
對驗證特性進行驗證的代碼大致如下:
//遍歷屬性
ValidationAttribute[] validationAttributes = //獲取驗證特性
foreach (var validation in validationAttributes)
{
if (validation is RegularExpressionAttribute)
{
var regularAttr = validation as RegularExpressionAttribute;
var reg = new Regex(regularAttr.Pattern);
if (value != null && !reg.IsMatch(value.ToString()))
return false;
}
else
{
ValidationResult result = validation.GetValidationResult(value, new ValidationContext(instance, null, null));
if (result != ValidationResult.Success)
return false;
}
}
這里之所以要將RegularExpressionAttribute單獨抽出來判斷是因為System.ComponentModel.DataAnnotations.dll(v4.0.0.0)內的實現有BUG,沒有根據正則正確的實現GetValidationResult方法。
效果
//實體
public class User
{
private string m_Name = null;
[Required(ErrorMessage = "用戶名不能為空!")]
[StringLength(10, MinimumLength = 4, ErrorMessage = "用戶名長度必須在4-10之間")]
[DisplayName("用戶名:")]
public string Name
{
get { return m_Name; }
set { m_Name = value; }
}
//略
}
//前端
<%
FormBuilder form = new FormBuilder();
User user = new User { Name = "測試", StateId = 2 }; %>
<%=form.CreateBeginHtml("/Handlers/MvcHandler.ashx", "fmTest")%>
<%=EasyUIHelper.ValidateText(u => u.Name, user)%>
<br />
<%=EasyUIHelper.Combobox(u => u.StateId, user, "States", "{ id: 'myCob', 'data-options': 'width: 100, editable: false'}")%>
<br />
<input type="submit" value="提交" />
<%=form.CreateEndHtml() %>
<script type="text/javascript">
$('#fmTest').easyuiForm();
</script>


結尾
謝謝大家,如文章有任何問題和錯誤請指出,謝謝!
