好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Project Silk – Mileage Stats 项目架构初步分析(ASP.NET MVC

Project Silk – Mileage Stats 项目架构初步分析(ASP.NET MVC 3) [转]

如果你正在学习 ASP.NET MVC 3 , HTML5 , jQuery 和浏览器客户端交互技术,推荐你下载 Mileage Stats 范例程序,可更好理解如何使用当前技术创建当前的 web 应用程序,尤其关注如何架构一个企业级的应用程序。关于 Mileage Stats 项目的初步介绍,请参考《 Project Silk – 基于 ASP.NET MVC 3 的示例应用程序 Mileage Stats 》。



EntLib测试数据 Team 尝试从架构的角度对 MileageStats 项目进行分析和解读,并计划运用到实际的电子商务系统中,欢迎大家参与交流和分享。



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);


            Vehicle vehicle = vehicles.First(v =>
v.VehicleId == vehicleId);


            var fillups = this .GetVehicleFillupsDescending(vehicleId);


 


            var viewModel = new
FillupViewModel ()


            {


                VehicleList
= new VehicleListViewModel (vehicles, vehicle) {
IsCollapsed = true },


                Fillups =
new SelectedItemList < FillupEntry >(fillups, model),


                FillupEntry
= model


            };


 


            this .ViewBag.IsFirstFillup = (fillups.Count ==
0);


 


            return this .View(viewModel);


        }




依赖注入 - Dependency
Injection


解耦应用程序的组件( Decoupling the application
components )。关于 Unity 2.0 依赖注入容器在 ASP.NET MVC 3 项目的具体使用细节,可参考文章 - 在 ASP.NET MVC 项目使用 Unity 2.0 实现依赖注入 。



创建 Business Service


为了项目的可维护和支持不同类型的客户端,大型和复杂的应用程序经常需要额外的架构层
– Business Service Layer ,将业务逻辑从数据访问层分离出来。



本文参考和编译了如下文章部分内容:


Project Silk 1.0 – Server-side Architecture


Project Silk - http://silk.codeplex测试数据/

作者: Leo_wl

    

出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于Project Silk – Mileage Stats 项目架构初步分析(ASP.NET MVC的详细内容...

  阅读:40次