天天看點

Project Silk – Mileage Stats 項目架構初步分析(ASP.NET MVC 3)

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,如需轉載請自行聯系原作者

繼續閱讀