ASP.NET MVC实用技术:开篇

ASP.NET MVC是一款基于ASP.NET的MVC模式的实现框架。通过使用ASP.NET MVC框架,开发人员能够非常方便地完成应用程序前台页面的开发工作。优秀的前台展示,对于大型企业级应用而言,是非常重要的组成部分,而ASP.NET MVC则为实现这一重要组成部分提供了技术和平台支持。目前,ASP.NET MVC已经到了4.0 Beta的版本,但我仍然打算以ASP.NET MVC 3为基础,通过几篇文章的篇幅,介绍一些ASP.NET MVC的实用技术,比如:如何实现自定义的认证机制、如何实现多主题效果的支持等。这些内容在网上也或多或少地提供了一些解决方案,但有些也不算太完整,有些又写的很含糊。因此,这几篇连载的文章会对每个实用技术进行完整的介绍,并在每篇文章结尾部分给出案例源代码及其使用方式,以供读者朋友们参考。

首先说明一下,这几篇文章不会对ASP.NET MVC中的概念进行描述,也不会太多地去深究某些技术实现细节,这些文章应该可以看成是几篇连载的“菜谱(Cook Book)”,读者朋友通过阅读并实践文中所述的内容,就能够获得所需的解决方案。虽然不能从根本上“解惑”,但也能在实践上为读者指明方向。此外,本人并不擅长.NET的前台技术,所以这几篇文章中提供的解决方案也不一定是最好的,如果读者朋友们有更好的想法或者思路,欢迎大家踊跃留言。

在介绍这些实用技术以前,首先让我们了解一下在企业级应用程序架构中,ASP.NET MVC的应用模式,这对我们今后介绍各种技术有一定的帮助,也算是能够让我们在架构的这个问题上达成一致。之后,我们再看看标准的ASP.NET MVC应用程序的数据库问题。

ASP.NET MVC的应用模式

在讨论ASP.NET MVC的应用模式时,对于MVC中的View和Controller的理解,我想应该不会存在什么太大的异议:View主要负责管理页面的显示布局和效果,并将Model中的数据展现在页面上;Controller则负责Model数据的获取与组织,并将数据以某种形式绑定到View上,或者从View上获取数据并对其进行必要的操作。现在需要讨论的是MVC中的这个“M”,从概念上讲,它应该是指View Model,因为它是View的数据源,但事实上在不同的应用程序中,它可能会被赋予不同的含义,于是也就产生了三种常见的ASP.NET MVC应用模式。比如,在实际项目中,我们有可能直接将Domain Model用作View Model,以便Controller能够直接操作Domain Model以完成业务逻辑处理;我们有可能把用于与分布式服务进行通信的数据传输对象(Data Transfer Objects)用作View Model,以便Controller能够通过分布式服务来获取或者提交数据,进而在分布式服务中对这些数据进行处理;我们还有可能在数据传输对象(Data Transfer Objects)与View Model之间再做一层映射,以解耦View Model与数据传输对象,因为在某些情况下View Model与数据传输对象仍然存在“阻抗失衡。针对这三种不同的应用模式,应用程序也会有着架构设计和部署上的差异。下面我们对这三种不同的应用模式进行详细讨论。

Domain Model as View Model

对于中小型应用程序而言,这种应用模式比较常见,在这种模式中,Domain Model被用作View Model,直接成为View的数据源,被显示在页面上。这有点像“数据源架构模式(Data Source Architectural Patterns)”中的Active Record模式。在Active Record模式中,对象用来表示数据库中的一张表或者一个视图,同时它又包含一些业务逻辑,于是,它混合了领域对象和数据访问对象的职责。在ASP.NET MVC中,如果采用Domain Model as View Model的模式,那么情况也就非常相似,因为这里的Model同时包含了领域模型和视图模型的职责。当然,除非是特殊情况,比如应用程序本身规模比较小,否则Domain Model as View Model并非一个合理的应用模式,它违背了软件设计的SRP(Single Responsibility Principle)的原则。

Domain Model as View Model的实现比较简单,只需要将Domain Model写在ASP.NET MVC Web应用程序中就可以了。为了能够参与View Model的职责,我们通常会在Domain Model上加入一些验证特性,比如使用RequiredAttribute来标注当前的属性是一个必填字段,以便基于javascript的客户端验证机制能够在必要的时候将错误信息提示给用户。在数据存储部分,通常可以选用ORM,将Domain Model直接持久化到数据库;也可以使用数据访问对象(Data Access Objects),配合使用ADO.NET来实现数据访问。常见的数据访问模式可以参考:Table Data GatewayRow Data GatewayActive Record以及Data Mapper

从物理部署的角度看,首先需要一台数据库服务器作为数据持久化基础架构,然后是一台IIS Web服务器,用来运行ASP.NET MVC Web应用程序,客户端浏览器通过访问这个IIS站点来完成系统交互。这是一个典型的三层结构,我用下图简要地描述了Domain Model as View Model的应用模式(说明:虽然将物理机器的部署和应用程序的逻辑结构画在一起并不是那么自然,毕竟逻辑视图和部署视图是两个完全不同的表述,但为了让读者能够看到在不同的物理部署节点上,运行着哪些逻辑组件,我还是勉强将它们画在了一张图中,因此如果在该图中如果有什么不合理的地方,还请读者指正):

image

 

Data Transfer Object as View Model

这种应用模式往往可以跟面向领域的架构模式相结合,提供比较合理的企业级应用程序解决方案。在这种应用模式中,领域模型不充当View Model的角色,它甚至与View Model毫无关系,只是作为一个业务组件运行在另一台物理服务器上。根据领域驱动设计(DDD)的实践指导,应用层通过仓储来管理领域对象的生命周期、使用这些领域对象和领域服务来完成所需的业务逻辑、并在领域对象与数据传输对象之间进行映射操作。当我们使用WCF作为服务供应者(Service Provider)时,通常会将WCF的Data Contract作为数据传输对象(Data Transfer Object),因此,应用层会完成Data Contract和领域对象之间的转换,然后通过WCF服务向外部提供服务接口。

作为向最终用户提供界面服务的ASP.NET MVC Web应用程序,它会通过服务引用(Service Reference)来使用由WCF公布的服务。在这个过程中,.NET会在ASP.NET MVC Web应用程序中创建一系列的WCF客户端代理类型,其中包括Client Channel、Data Contracts等。于是,MVC中的Controller会调用WCF服务以获得Data Contract对象,之后将这些Data Contract对象作为View的数据源绑定到View上。因此,整个过程事实上是使用数据传输对象作为View Model。类似地,我也针对这种应用模式画出了整个应用程序的结构细节,读者可以与上图进行比较:

image

在这种应用模式中,ASP.NET MVC不再参与任何业务逻辑,它仅仅是为用户界面提供服务,这样就完全解耦了用户界面层与业务层之间的关联关系。也就是说,我们可以不选用ASP.NET MVC技术,而选择其它的展现层技术(比如WPF或者Windows Forms)来设计和开发应用程序的展现部分。而在业务逻辑部分,基本上可以以DDD为指导进行设计与开发,这样做不仅可以将大部分分析与设计的精力放在领域模型上,而且还能够很自然地(或者说更合理地)应用一些企业架构模式。

这里其实会有一个技术问题,就是在ASP.NET MVC部分,Data Contract代理类型都是在Service Reference的过程中自动产生的,如果将这些Data Contract,也就是数据传输对象,直接作为View Model绑定到View上,那么似乎那些用于客户端验证的Attributes就无法添加到这个View Model上。事实上我觉得MS应该已经意识到了这种应用的可行性,所以已经有现成的解决方案了。这个解决方案得益于两件事情:C#的partial class,以及MetadataTypeAttribute。

比如,在自动生成的代理类中,有如下这个Data Contract:

[DataContract]
public partial class Customer {
  [DataMember]
	public string Name { get; set; }
}

那么我们可以使用下面的方法为Customer的Name属性添加验证规则:首先,针对Customer定义一个Metadata类,使其包含与Customer相同名称的属性(当然,只需要包含那些你需要添加验证特性的属性即可),然后在这个Metadata类的属性上,添加验证特性,如下:

public class CustomerMetadata {
	[Required(ErrorMessage="Name must be specified.")]
	public string Name { get; set; }
}

之后,使用partial关键字重定义Customer类,并在这个partial类上使用MetadataTypeAttribute,将CustomerMetadata“绑定”到Customer类即可:

[System.ComponentModel.DataAnnotations.MetadataTypeAttribute(typeof(CustomerMetadata))]
partial class Customer { }

Data Transfer Object as View Model的应用模式同时也向我们展示了.NET技术在领域驱动设计实践中的应用。接下来的几篇文章,都会以这种应用模式为背景,对ASP.NET MVC的一些实用技术进行介绍。

Mapped DTO as View Model

Mapped DTO,也就是根据View的需求,通过映射技术,将数据传输对象组装成View所需的View Model。其实与Data Transfer Object as View Model相比,它只是在View Model和Data Transfer Object之间又增加了一层映射处理,应用程序的其它部分与DTO as View Model完全相同。这种映射处理可以使用一些辅助的第三方框架(比如AutoMapper等)完成。在这里,我也就不打算对这种应用模式进行详细介绍了。

ASP.NET MVC应用模式大致也就是上述几种,这些讨论都是以MVC中的“M”为中心展开的。为了能够开始接下来的实用技术介绍,在此还需要简单地讨论一下ASP.NET MVC应用程序的数据库部分。

ASP.NET MVC应用程序的数据库

每当我们新建一个ASP.NET MVC应用程序的时候,Visual Studio模板都会帮我们把整个项目都建好,并会默认地使用SQL Server Express作为这个应用程序的后台数据库。如果你的机器上装有SQL Server Express,那么在你第一次运行ASP.NET MVC应用程序后,你应该就会在App_Data下找到一个aspnetdb.mdf的数据库文件,所有与ASP.NET MVC应用相关的数据表都会保存在这个数据库文件中。

当然,在大多数情况下,你有可能不会将SQL Server Express用作上线系统的数据库,或许你更倾向于使用SQL Server 2008 Enterprise Edition作为你的后台数据库,那么你就需要定制ASP.NET MVC应用程序。首先,打开Visual Studio 2010 Command Prompt,在命令行输入aspnet_regsql然后回车,这将打开ASP.NET SQL Server Setup Wizard:

image

在这个界面上单击Next按钮,在Select a Setup Option选项卡中,选择Configure SQL Server for application services选项,然后单击Next:

image

在Select Server and Database选项卡中,选择你要使用的数据库名称,然后单击Next:

image

在Confirm Your Settings选项卡中直接单击Next按钮,这样,向导就会将所需的数据库对象同步到你所选择的数据库中,然后在完成页面单击Finish按钮:

image

回到SQL Server管理控制台,展开我们刚刚创建的数据库,我们可以看到,所有所需的数据库对象都已经创建好了:

image

现在,回到ASP.NET MVC应用程序,在web.config中把数据库连接字符串直接改掉就可以了。

如果你的应用程序采用了上述“Data Transfer Object as View Model”的模式,那么你的后台数据库又将是另外一个景象:它或许连这些ASP.NET MVC所需的数据库对象都没有,于是你只能够自定义Membership Provider,然后在ASP.NET MVC中使用这个自定义的Membership Provider。在Tiny Library CQRS案例中已经采用了自定义的Membership Provider,有兴趣的读者可以先去了解一下,不过这部分内容也会在后续的篇章中详细介绍。

总结

本文为《ASP.NET MVC实用技术》系列文章的开篇,首先对ASP.NET MVC的应用模式进行了简单介绍,然后浏览了一下与ASP.NET MVC程序数据库相关的一些内容。在接下来的文章中,我会以ASP.NET MVC 3为基础,详细介绍一些实用技术,并会在每篇文章末尾给出完整源代码案例,供读者参考使用。

扩展阅读

有兴趣的读者可以参考以下资料,以对ASP.NET MVC的应用模式作进一步了解:

 

posted @ 2012-03-16 15:47 dax.net 阅读(...) 评论(...) 编辑 收藏