MileageStats RI 運作的主要界面:
MileageStats RI 項目的目前架構圖,主要有Web 表示層、業務邏輯層和資料通路層,如下圖所示。
簡要看看MileageStats 包含的一些主要項目:
建立資料模型(Data Model)
MileageStats.Model 項目包含資料模型(Data Model)。結構化和強類型的類描述了業務資料的資料類型、關系和限制。
實作Repository Pattern
在Repository模式中,Repository是一組接口,實作了資料通路相關的方法。接口沒有暴露任何特定資料存儲相關的類型。
MileageStats.Data 項目包含了Repository接口,MileageStats.Data.SqlCe 項目包含了接口的實作。如下是IReminderRepository 接口的示例代碼:
// contained in IReminderRepository.cs
public interface IReminderRepository
{
void Create(int vehicleId, Reminder reminder);
Reminder GetReminder(int reminderId);
void Update(Reminder reminder);
void Delete(int reminderId);
IEnumerable<Reminder> GetRemindersForVehicle(int vehicleId);
IEnumerable<Reminder> GetOverdueReminders(int vehicleId,
DateTime forDate, int forOdometer);
IEnumerable<Reminder> GetUpcomingReminders(int vehicleId,
DateTime forStartDate, DateTime forEndDate,
int odometer, int warningOdometer);
IEnumerable<Reminder> GetFulfilledRemindersForVehicle(int vehicleId);
}
分解應用程式代碼到ASP.NET MVC模式
設計良好的MVC應用程式保持Controller和Action方法比較小,View比較簡單。大部分的核心應用程式邏輯存放在Model中。在MVC應用程式建立時,保持DRY(Don’t Repeat Yourself)原則比後期試圖清理代碼更容易。
因為大部分應用程式邏輯在Model層中,是以很多MVC 應用程式包含不同類型的Model:
l View models(視圖模型) - 僅用于視圖的資料綁定,這些Models包含于MVC 應用程式中,一般與Views和Partial Views保持相同的構成結構。
l Application, domain, or service models(業務模型) - 基于實際業務需要建立的資料模型,可添加屬性标注,或擴充支援應用功能,如資料驗證、身份驗證。因為這些Models易于往返于用戶端浏覽器,是以它們經常包含于View Models,并直接在HTML 表單進行資料綁定。
l Data models(資料模型) - 用于資料服務和存儲,不會暴露在應用程式之外,經常封裝在服務層。
如下是MileageStats RI Solution中包含的3個Model項目 – 下圖中選中的項目,分别在Web層、業務邏輯層和資料層:
對于比較複雜或長期維護的應用程式,應該分離業務模型和資料模型。如果業務模型和資料模型的層級和接口差異很大,則建立完全分離的類。如業務模型和資料模型有比對的層級和相容的接口,則建議業務模型類繼承資料模型類。如業務模型和資料模型有比對的層級,但接口不相容(如資料模型類接口不适合于業務模型類),則在業務模型類中通過聚集關系,包含資料模型類執行個體。
在編寫Controller Action方法時,應将一些複雜的方法包裝為model和service層的輔助方法或類中。優先采用action過濾器屬性,如HttpPostAttribute,避免在每一個action方法中檢測HttpContext,編寫邏輯判斷。此外,使用action過濾器進行橫切關切點(Cross-cutting concern),如認證(AuthorizeAttribute)、錯誤處理(HandleErrorAttribute)等等。處理GET請求的方法應僅包含一些方法調用,而不必包含太多業務判斷邏輯;處理POST 請求的方法應驗證傳入的資料,在資料合法的情況下,執行更新操作,并根據更新結果,傳回對應視圖。MileageStats RI 應用程式的如下範例顯示2個版本的Add方法(分别為GET和POST版本):
// GET: /Fillups/Add/1
public ActionResult Add(int vehicleId)
{
var vehicles = this.businessServices.GetVehicles(this.User.MileageStatsIdentity().UserId);
Vehicle vehicle = vehicles.First(v => v.VehicleId == vehicleId);
var newFillupEntry = new FillupEntry()
{
Odometer = vehicle.Odometer.HasValue ? vehicle.Odometer.Value : 0
};
var fillups = this.GetVehicleFillupsDescending(vehicleId);
var model = new FillupViewModel()
VehicleList = new VehicleListViewModel(vehicles, vehicle) { IsCollapsed = true },
Fillups = new SelectedItemList<FillupEntry>(fillups, newFillupEntry),
FillupEntry = newFillupEntry
this.ViewBag.IsFirstFillup = (fillups.Count == 0);
return this.View(model);
}
//
// POST: /Fillups/Add/5
[HttpPost]
[ValidateInput(false)]
[ValidateAntiForgeryToken]
public ActionResult Add(int vehicleId, FillupEntry model)
if (this.ModelState.IsValid)
this.AddModelErrors(this.businessServices.CanAddFillup(this.CurrentUserId, vehicleId, model),
"AddFillup");
if (this.ModelState.IsValid)
{
this.businessServices.AddFillupToVehicle(this.CurrentUserId, vehicleId, model);
this.TempData["LastActionMessage"] = Resources.VehicleController_AddFillupSuccessMessage;
return this.RedirectToAction("List", "Fillup", new { vehicleId = vehicleId });
}
}
var vehicles = this.businessServices.GetVehicles(this.CurrentUserId);
var viewModel = new FillupViewModel()
Fillups = new SelectedItemList<FillupEntry>(fillups, model),
FillupEntry = model
return this.View(viewModel);
依賴注入 - Dependency Injection
建立Business Service 層
為了項目的可維護和支援不同類型的用戶端,大型和複雜的應用程式經常需要額外的架構層 – Business Service Layer,将業務邏輯從資料通路層分離出來。
本文參考和編譯了如下文章部分内容:
Project Silk 1.0 – Server-side Architecture
本文轉自 entlib.com 51CTO部落格,原文連結:http://blog.51cto.com/entlib/569205,如需轉載請自行聯系原作者