本文提供了一些代碼設計準則,目標是協助ASP.NET MVC 開發人員建立可靠的應用程式,當然,你可根據實際應用程式選擇合適的標準。本文由EntLib.com 小組翻譯,歡迎分享和交流ASP.NET MVC 項目開發設計思路。
Model建議 - Model Recommendations
Model是定義業務領域相關的對象,應該包含商務邏輯(對象如何動作和關聯),驗證邏輯(驗證對象的有效值),資料邏輯(資料對象如何持久化),和會話邏輯(跟蹤使用者狀態)。
建立獨立的Model項目,在ASP.NET MVC 項目中引用Model程式集。
將所有商務邏輯放置在Model中。
如將所有商務邏輯放置在Model項目中,可根據實際業務資料來產生View和Controller。有如下好處:
- 減少重複的商務邏輯。
- 在View中減少商務邏輯,View易於理解。
- 商務邏輯的測試僅僅和Model有關。
例如,下面需要顯示使用者的使用者名稱 – 先顯示Last Name,在View中代碼如下:
<% if (String.Compare((string)TempData["displayLastNameFirst"], "on") == 0)
{ %>
Welcome, <%= Model.lastName%>, <%= Model.firstName%>
<% }
else
{ %>
Welcome, <%= Model.firstName%> <%= Model.lastName%>
<% } %>
然而你需要在每一個地方重複這一邏輯。如將這一商務邏輯放置在Model中,可在Model中添加一個屬性封裝這一邏輯。
public string combinedName
{
get
{
return (displayLastNameFirst ? lastName + " " + firstName : firstName + " " + lastName);
}
private set
{
;
}
}
這樣,可大大簡化視圖代碼:
<% Welcome, <%= Model.combinedName %> %>
將所有驗證邏輯放置在Model中
所有輸入驗證應該在Model層,包括Client-side 驗證。
可使用ModelState 添加驗證檢查,代碼如下所示:
if (String.IsNullOrEmpty(userName))
{
ModelState.AddModelError("username", Resources.SignUp.UserNameError);
}
不過,更好的辦法是使用 System.ComponentModel.DataAnnotations,在Model類的屬性上添加attribute,如下所示:
public class User
{
[Required(ErrorMessageResourceName = "nameRequired", ErrorMessageResourceType = typeof(Resources.User))]
public String userName { get; set; }
...
}
為資料訪問定義介面
介面用來暴露資料訪問類的方法,強化ASP.NET MVC 的鬆散耦合設計。
可考慮使用Entity Framework 或 LINQ to SQL 建立對資料庫的訪問類,Entity Framework 和 LINQ to SQL 都支援預存程序。
將所有會話邏輯放置在Model中。
View 建議 - View Recommendations
View用來展示Model資料,Controller負責選擇View。商務邏輯不屬於View,Model負責商務邏輯。View非常靈活,如Model的View可通過HTML顯示,同樣的Model也可通過XML 視圖來呈現。
將HTML放置在View和Partial View中(不要在Controller中)
預設的ASP.NET視圖引擎提供了如下視圖檔案:HTML View(.aspx),Partial HTML View(.ascx)和Master page(.master)
如下視圖示範了對partial view的調用:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
…
Below is a list of items submitted by <b>
<%= Html.Encode(ViewData["name"]) %></b>.
<p>
...
<div id="items">
<% Html.RenderPartial("ItemsByName");%>
</div>
</asp:content>
Partial view(ItemsByName.ascx)如下所示:
<%@ Control Language="C#" %>
…
<% foreach (Seller.Controllers.Items item in (IEnumerable)ViewData.Model)
{ %>
<tr>
<td>
<%= Html.Encode(item.title)%>
</td>
<td>
<%= Html.Encode(item.price)%>
</td>
</tr>
<% } %>
</table>
<% } %>
Partial View 是一個強大的擴充和重用機制。你可在不同的地方包含相同的View,不必編寫重複的代碼。
在View中使用ViewData訪問資料
ASP.NET 提供了如下機制在View模板中訪問資料:
ViewData.Model 對象 – 在Controller的action方法中,在return語句中傳入一個Model對象(return View(myModelObject))。
ViewData Dictionary – 在action方法中存入資料(ViewData[“key”] = value),接著在View中方法相同的dictionary。
在可能的情況下,應該是一ViewData Model,而不是ViewData 來訪問資料,因為Model 提供了型別安全。此外,你應在View模板中,使用資料訪問機制,而不是Request / Session 來訪問。
如需要顯示一個對象的多個屬性,可使用ViewData.Model,並建立一個強型別View。針對seller詳細頁面,seller類有name、phone、address、email等等屬性,在呈現View之前,你可在Controller中對ViewData.Model 賦值seller對象執行個體。但是如果是一些零散的資料,如page#、使用者名稱和current time,則一般使用ViewData字典。
在使用模型繫結(Model bingding)時,避免在view中訪問資料。
在Controller 中訪問資料庫,在執行View之前,將從資料庫中檢索的資料複製給輕量的View Model對象,這樣,輕量的View Model對象不必在視圖執行時檢索資料。
使用(自動產生)用戶端驗證
從ASP.NET MVC 2 開始,可以很容易添加用戶端驗證。
(1) 如前所述,在Model層中添加資料驗證邏輯;
(2) 確保項目中Scripts目錄有如下javascript 檔案:MicrosoftAjax.js 和 MicrosoftMvcValidation.js;
(3) 在表單提交頁面,添加如下代碼:
<script src="<%= Url.Content("~/Scripts/MicrosoftAjax.js") %>" type="text/javascript"></script>
<script src="<%= Url.Content("~/Scripts/MicrosoftMvcValidation.js") %>" type="text/javascript"></script>
(4) 在表單中添加如下代碼:
<% Html.EnableClientValidation(); %>
現在如果編輯表單內容,當輸入值不合格時,用戶端馬上進行驗證提醒。
在模板中插入server-side 注釋
在View模板中使用服務端注釋,在HTML呈現時,會剔除。
如下是server-side注釋:
<%-- This is a server side template comment --%>
不要在View模板中使用HTML 注釋,因為這些注釋會呈現在web瀏覽器中,可被使用者看到。
使用HTMLHelper 擴充方法。
System.Web.Mvc.Html 類中包含了很多有用的HTML 延伸方法。
Form 表單產生(BeginForm)
輸入欄位產生(checkbox、hidden、radio button、textbox)
連結URL產生(ActionLink)
XSS保護(Encode)
儘可能使用這些HTML擴充方法,如下是使用route table建立一個連結:
<%= Html.ActionLink(“Home page”, “Default”) %>
後續相關文章,可參考如下連結:
ASP.NET MVC 最佳開發實踐(2)
ASP.NET MVC 最佳開發實踐(3)
英文原文連結:
Best Practices for ASP.NET MVC
http://blogs.msdn.com/b/aspnetue/archive/2010/09/17/second_2d00_post.aspx