专栏首页张善友的专栏ASP.NET MVC 2示例Tailspin Travel UI层分析

ASP.NET MVC 2示例Tailspin Travel UI层分析

Tailspin Travel 是一个旅游预订的应用程序示例,最新版本采用ASP.NET MVC 2技术构建,主要使用 DataAnnotations 验证, 客户端验证和ViewModels,还展示了许多Visual Studio 2010, .NET Framework 4, 和Windows Server AppFabric的技术,参看ASP.NET MVC 2示例Tailspin Travel

Tailspin Travel设计的技术比较多,今天我们来看看界面(UI)上的技术,在UI层上来说主要采用的技术是ASP.NET MVC2和ASP.NET DynamicData框架。从功能上来分为向普通用户提供的前台页面和管理员使用的后台界面,前台页面主要实现的是旅游活动日程安排,航班,酒店,租车这几部分采用的ASP.NET MVC 2技术,管理员用的后台管理页面使用的是ASP.NET DynamicData开发的,这两种技术在网站里的应用有示范作用,对于管理员使用的后台的访问量不可能很大,网站的主要流量是普通用户使用的前台页面,组合使用这两个框架,可以加快网站的开发。

组合这两种技术,就会碰到一些的问题,第一个问题就是ASP.NET 动态数据(Dynamic Data )默认情况下,动态数据放在web应用的动态数据目录(DynamicData)里,该目录创建在根目录处。你的应用需要移动的不同的位置。 在Tailspin Travel里面是“admin”目录,动态数据就在这个目录下,然后在Globa.asax.cs文件里

var metaModel = new MetaModel();    
metaModel.RegisterContext(contextFactory, new ContextConfiguration { ScaffoldAllTables = true });     
metaModel.DynamicDataFolderVirtualPath = "~/Admin/DynamicData/";

改变admin/Dynamicdata 下文件的内容的引用到新的路径((~/admin/Dynamicdata) 例如: A、修改List.aspx和ListDetails.aspx 的注册指令的src属性。 B、修改 List.aspx 和母版页的img 的src属性。 C、任何自定义的必须使用新路径的内容。

ASP.NET 4.0有个新特性叫做“自动启动应用程序”,自动启动,先行初始化web应用,而不必等待外部客户端访问web服务器时才启动的能力。这可以有助于你给第一个访问者提供一个更快的回复体验,避免撰写定制脚本来“预热(warm up)”服务器和准备好任何数据缓存。它可用于任何类型的ASP.NET应用,包括基于ASP.NET Web Forms和ASP.NET MVC的应用。不过要求在IIS 7.5(随Windows 7和Windows Server 2008 R2发布)上运行 ASP.NET 4时使用。这个自动启动特性提供了一个可控制的方式来启动一个应用工作进程,初始化ASP.NET 应用,然后接受HTTP请求。具体参看Scott Guthrie 的文章 VS 2010 和 .NET 4.0 系列之《自动启动ASP.NET应用》篇,Tailspin Travel有个类Microsoft.Samples.Tailspin.Web.Infrastructure.ApplicationPreloader,就是用这个特性预先加载应用程序的缓存。

下面我们来具体分析前台和管理后台:

前台采用ASP.NET MVC 2开发,比较简单,主要是使用ViewModels,HtmlHelper,输出缓存,避免CSRF攻击,查询方法中使用PartialView,以及jQuery和ASP.NET Ajax配合的相关内容,可以参考 Asp.net MVC2 使用经验,性能优化建议学习。

下面重点来说明一下管理后台的DynamicData的结构,先可以阅读一下Scott Guthrie 的文章 新的ASP.NET动态数据支持

ASP.NET 动态数据在进行创建和更新数据时还会对所录入的数据进行验证,这种验证既发生在客户端也发生在服务器端。

  • 必填字段验证。如果字段不允许为 NULL,则录入时必须录入数据。不过这里还有待改进,不允许为 NULL,也就成了不允许零长度字符串,而实际应用中 NULL 和零长度字符串是两回事。纵然不够完美,也已经为我们减轻不少工作量了。
  • 长度验证。如果字段类型为 nvarchar(10),那么就不允许超过 10 个字符;如果字段类型不是 nvarchar(10),而是 varchar(10),此时六个汉字也会通过验证,只是无法入库罢了,会返回错误。
  • 类型验证。比如字段是日期类型,则只允许录入日期。

ASP.NET 动态数据具有自动格式功能:比如 bit 类型的字段显示为一个多选框,而标识字段不会在插入数据时显示出来。

ASP.NET 动态数据还具有自动识别表关联的功能:比如产品表与产品类别表进行了关联,那么我们在录入产品数据的时候,ASP.NET 动态数据会自动以下拉列表的形式显示产品类别。此功能非常不错。

在网站或者应用程序模板中有两个Dynamic Data模板,一个是 "Dynamic Data实体模板(Dynamic Data Entities )"它是使用ADO.net Entity作为数据模型的,另一个是 "Dynamic Data 模板",他是使用LINQ TO SQL 来作为数据模型。Tailspin Travel 是以Entity Framework作为数据模型的。

Dynamic Data也使用了Routing:

            routes.Add(new DynamicDataRoute("Admin/{table}/{action}")    
            {     
                Constraints = new RouteValueDictionary(new { action = "List|Edit|Details|Insert" }),     
                Model = metaModel     
            });

routes.Add 的参数为一个 DynamicDataRoute 对象,而该 DynamicDataRoute 对象有一个参数为 "Admin/{table}/{action}.aspx",另外还为该对象指定了两个属性值 Constraints 和 Model。把一个继承自Route的DynamicDataRoute添加到Routing规则表中。

Constraints = new RouteValueDictionary(new { action = "List|Details|Edit|Insert" }) 这句表示约束,这里表示 action 只能是 List、Details、Edit、Insert 中的一个。

可以看出,这四个Aciton是对应着DynamicData/PageTemplates文件夹中的四个页面文件。在那文件夹中还有一个ListDetails.aspx页面文件,是用于"合并页模式",就是所有的操作都会在一页中完成。Tailspin Travel并没有启用这个功能。DynamicData 文件夹的名称都是“DynamicData”。

上面的 {table}、{action} 可不可以改成我们自己想要的名字呢?

不行的,我们可以看到,上面使用的是 DynamicDataRoute 类,而不是 Route 类,DynamicDataRoute 继承于 Route,Table 和 Action 属性是 DynamicDataRoute 特有的。

DynamicData/Content/GridViewPager.ascx 分页控件。

DynamicData/Content/FilterUserControl.ascx 在显示表中的数据时,该控件显示在表头,用以过滤表中的内容,比如可以只列表产品目录为“实用工具”的产品。

DynamicData/CustomPages 文件夹。自定义网页模板文件夹,可用以替换 DynamicData/PageTemplates 文件夹中的默认模板。

DynamicData/FieldTemplates 文件夹。包含各种类型的字段在查看和创建、编辑时所呈现的控件。

DynamicData/PageTemplates 文件夹。包含在进行查看、编辑时的页面模板。

Dynamic Data还有一个快速开发的基础是脚手架,脚手架是一种机制,通过脚手架,我们不必再为每一个表的增加、查看、修改做不同的页面,因为脚手架会自动生成这些页面。Tailspin Travel对所有表都启用脚手架,对所有表启用脚手架表示公开了整个数据模型:

metaModel.RegisterContext(contextFactory, new ContextConfiguration { ScaffoldAllTables = true });

还可以对特定表启用脚手架功能,这时就要将上面的ScaffoldAllTables = false,然后给模型类打标签[System.ComponentModel.DataAnnotations.ScaffoldTable(true)]

自动生成的网站需要我们调整的页面,需要创建自定义的页面可以把它放在DynamicData/CustomPages 文件夹,在 DynamicData/CustomPages/ 下新建一个文件夹,名称为 FlightBookings,这个名称一定要与 Tailspin.edmx中的相应表的分部类名称一样。然后将 DynamicData/PageTemplates/ 下的文件复制到 DynamicData/CustomPages/FlightBookings/。

更改新模板文件中的类名。

比如将类名称 List 改为 DynamicDataTest.FlightBookingsList

使用DisplayName更改界面的显示,DisplayName 只能用于类、方法、属性、索引、事件

[MetadataType(typeof(CarRentalMetadata))]    
    public partial class CarRental     
    {     
        [ScaffoldTable(false)]     
        private class CarRentalMetadata     
        {     
            [DisplayName("Pick up")]     
            public object RentalStart { get; set; } 
            [DisplayName("Return")]    
            public object RentalEnd { get; set; } 
            [DisplayName("Pick up Place")]    
            [Required(ErrorMessage = "Please specify where you prefer to pickup the vehicle.")]     
            public object PickupPlaceId { get; set; } 
            [DisplayName("Return place")]    
            [Required(ErrorMessage = "Please specify where you prefer to return the vehicle.")]     
            public object ReturnPlaceId { get; set; } 
            [DisplayName("Vehicle")]    
            [Required(ErrorMessage = "Please specify the vehicle type.")]     
            public object VehicleTypeId { get; set; }     
        }     
    }

还可以用 UIHint,DataType 改变字段模板

[MetadataType(typeof(FlightMetadata))]    
    public partial class Flight     
    {     
        public Flight()     
        {     
            this.Id = Guid.NewGuid();     
        } 
        [DisplayName("Flights")]    
        private class FlightMetadata     
        {     
            [ScaffoldColumn(false)]     
            public object Id { get; set; } 
            [Required]    
            public object AirplaneType { get; set; } 
            [UIHint("Time")]    
            public object DepartureTime { get; set; } 
            [UIHint("Time")]    
            [DataType(DataType.Time)]     
            public object ArrivalTime { get; set; } 
            [DisplayName("Departure Airport")]    
            public object DepartureAirport { get; set; } 
            [DisplayName("Arrival Airport")]    
            public object ArrivalAirport { get; set; }     
        }     
    }

DynamicData非常的灵活,Tailspin Travel用来对付管理后台的开发方面具有非常高的效率,在前台使用MVC2保证性能,在UI界面的开发方面非常值得借鉴的一种模式。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ASP.NET开发人员需要学习ASP.NET MVC么?

    InfoQ上有篇文章ASP.NET开发人员需要学习ASP.NET MVC么? 文章已经覆盖了绝大多数对于学习/使用ASP.NET MVC的观点。 我觉得ASP....

    张善友
  • ASP.NET 5 Beta 8 发布

    ASP.NET 5 的路线图(详见 ASP.NET 5 Schedule and Roadmap : https://github.com/aspnet/hom...

    张善友
  • ASP.NET 5 Beta 7 版本

    在 VS2015 发布的同时,微软也发布了 ASP.NET 5 的路线图(详见 ASP.NET 5 Schedule and Roadmap : https:/...

    张善友
  • ASP.NET MVC 5 - 添加一个模型

    在本节中,您将添加一些类,这些类用于管理数据库中的电影。这些类是ASP.NET MVC 应用程序中的"模型(Model)"。 您将使用.NET Framewor...

    葡萄城控件
  • Contest 176 LeetCode 1354. Construct Target Array With Multiple Sums(优先队列,递推)

    题意:举例:给你一个数组[9,3,5],问你这个数组是否可以由数组[1,1,1]经过某种变换得到。

    ShenduCC
  • WCF技术剖析之二:再谈IIS与ASP.NET管道

    在2007年9月份,我曾经写了三篇详细介绍IIS架构和ASP.NET运行时管道的文章,深入介绍了IIS 5.x与IIS 6.0HTTP请求的监听与分发机制,以及...

    莫问今朝
  • IIS 5.x与ASP.NET

    我们先来看看IIS 5.x是如何处理基于ASP.NET资源(比如.aspx,.asmx等)请求的,整个过程基本上可以通过图1体现。

    莫问今朝
  • WCF技术剖析之二:再谈IIS与ASP.NET管道

    在2007年9月份,我曾经写了三篇详细介绍IIS架构和ASP.NET运行时管道的文章,深入介绍了IIS 5.x与IIS 6.0HTTP请求的监听与分发机制,以及...

    蒋金楠
  • 基于业务对象(列表)的筛选

    可能大家对SQL语句太过熟悉了,也可能虽然已经从Asp过度到了Asp.Net时代,但是Asp的观念没有发生太大变化。结果就是我们将应用程序大部分的逻辑都交给了数...

    张子阳
  • HashSet内部原理解析Header源码解析Footer

    俞其荣

扫码关注云+社区

领取腾讯云代金券