玩转C科技.NET

从学会做人开始认识这个世界!http://volnet.github.io

导航

ASP.NET MVC Beta的一些更新plus

阅读本文需要具备一定的MVC的知识,最好有了解过源码的各个模块的工作方式。这样对这些细节将会有比较深刻的认识。(引自本文最末)

2008年10月15日,MVC更新到了Beta了,当然相对于Preview5也做了些许改进,这里就一些新的改进做一下罗列,非详解:(下载Beta

程序集将被增加到GAC中

其实大家在下载了Beta的Installer包安装完后会在“开始”->“程序”中看到一个文件夹,点开就能找到那些dll文件了。也可以拷贝

%ProgramFiles%\Microsoft ASP.NET\ASP.NET MVC Beta

这个地址到地址栏。它被安装在GAC中将意味着它是FullTrust的了。而之前的预览版中它们是通过模板脚本,在新建项目的时候preview的dll文件会被拷贝到相应项目的bin目录下。当然我们也是可以再次进入那个文件夹下把dll拷贝到你自己的项目中,而不依赖于当前系统,这样做通常可以在你发布一些演示项目的副本,或者是将你的项目拷贝到一些没有安装MVC至GAC的主机中运行。

从Preview3到MVC Beta的一些更新

准确地讲,上一个版本的更新应该是从Preview5的一些更新,但是因为http://www.asp.net/mvc网站只更新到了Preview3,Preview4和5只在Codeplex上进行了一下更新,这样对版本跟进不是比较及时的朋友可能就不知道那些新的更新了。这里微软也整理出了很多新的特性,这里做一下简单的罗列,具体细节以后可以再谈。

1、增加了AccountController

从名字上我们可以知道这是一个Controller,这也是MVC一直以来的一项约定,这个Controller的作用是利用这个类可以方便地访问Membership API,我们可以通过修改web.config来更改一些设置。MVC的模板也是被安装在账户下的:

盘符:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\ProjectTemplates\CSharp\Web\1033 或者

盘符:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\ProjectTemplatesCache\CSharp\Web\1033\MvcWebApplicationProjectTemplateBeta.cs.zip

在这里你可以很方便地找到AccountController的一些具体实现细节,当然你在生成项目后也会看到它,这里有便于您部署您自己的模板。顺便告诉你那些install文件在你机器上安装了哪些文件。

2、增加了验证和异常的处理

因为验证始终是大部分网站或者说应用程序必须具备的一项工作,而异常则几乎遍及所有的程序,作为一个通用的框架必然要解决这两个问题。MVC框架很早就引入了IAuthorizationFilter和IExceptionFilter两个接口用来扩展这方面的问题。

这两个接口都很简单,这得益于整个MVC框架的精简。

public interface IAuthorizationFilter {
    void OnAuthorization(AuthorizationContext filterContext);
}
public interface IExceptionFilter {
    void OnException(ExceptionContext filterContext);
}

怎么样,是不是出乎意料?为了方便使用,MVC框架实现了两个默认的Attribute用来方便的使用他们。AuthorizeAttribute和HandleErrorAttribute,这两个分别是以上两个接口的默认实现,因为是FilterAttribute因此和所有的FilterAttribute一样可以横向截获context进行处理,这样我们的使用就只需要在ActionResult方法上使用[Authorize(Users = “volnet,gong cen”))]类似的方式来验证就可以了。

3、输出缓存(Output Cache)

这个概念在ASP.NET WebForm模型中就已经很常见了,在Page中指定<@ OuputCache ……>就可以对页面进行缓存了,缓存的内容还是比较丰富的,有很多的可调控选项,不过最终因为太过细微而用的人不多。但是这是一个很优秀的特性,因此,MVC中还是提供了相关的属性。准确地讲二者调用了同一个Cache的模块。

private OutputCacheParameters _cacheSettings = new OutputCacheParameters();

帮大家找到个不错的示例,使用看它就好了:《How to: Add Output Caching to an Action Method

4、一些ASP.NET Ajax方面的改变

这里不是说去改变ASP.NET Ajax原本的框架,而是做一些专用的扩展,而这些扩展对我们是不可见的。这里我们需要注意的是新增的两个方法,它们都被放置在AjaxExtensions.cs文件内,一个是ActionLink,另一个是BeginForm。这两个方法都有N多的重载,最后其实也就做了一件事,ActionLink生成了一个Ajax形式的(string)<a href=”…” onclick=”…” />而BeginForm则返回了一个(MvcForm)<form action=”…” method=”post” onsubmit=”…”>。它们全都是AjaxHelper的扩展方法,至于生成什么Ajax脚本则是由AjaxOptions参数决定的了。他们跟HtmlHelper.ActionLink以及HtmlHelper.BeginForm具备类似的功能,就是他们被放在了AjaxHelper下了,而且从文件名结构可以臆断(其实就是)AjaxHelper的一堆扩展方法。

5、Routes命名空间

怎么说呢,这个应该是设计上的一个妥协,原来的priview中,MVC框架要去查找所有的类型系统以寻找controller的实现,但是发现有的controller可能继承自另一个类,而那个类所引用的程序集竟然没有载入,这样就抛出了异常了,很是尴尬!

于是引入了ControllerBuilder,它里面有个DefaultNamespaces,我们可以在void Application_Start(object sender, EventArgs e)中向这个HashSet<string>添加Controller的名字。

void Application_Start(object sender, EventArgs e) {
    ControllerBuilder.Current.DefaultNamespaces.Add("MyApp.Controllers");
    ControllerBuilder.Current.DefaultNamespaces.Add("MyApp.Blog.Controllers");
    ControllerBuilder.Current.DefaultNamespaces.Add("ThirdPartyApp.Controllers");
);
这样过程基本是这样的:
启动程序,然后Namespaces被存起来了,然后遍历程序集(由IBuilderManager.GetRefrencedAssemblies()提供),找出所有的Controller的Type取出来,整理到一个cache表中,表按Controller名分组,然后再按controllerName在命名空间中找(这里命名空间将成为ILookup子表的key),这样只需找出指定命名空间范围内的Controller即可,如果没有提供namespace则将所有的同名controller返回。当然了,在通过指定命名空间的范围内是有可能找不到对应Controller的,这样就会再次将所有的同名controller找出来。
这样看来这个Namespaces可以改变一下controller的执行。
涉及一下最后一部分的源码,其他代码大家可以自己去研究:
HashSet<string> nsDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
match = GetControllerTypeWithinNamespaces(controllerName, nsDefaults);
if (match != null) {
    return match;
}

// if all else fails, search every namespace
return GetControllerTypeWithinNamespaces(controllerName, null /* namespaces */);
另外也可以对不同的Routes指定不同的Namespaces

6、增强了TempData的可测试性

这个增强表现在抽象了ITempDataProvider接口:

public interface ITempDataProvider {
    IDictionary<string, object> LoadTempData(ControllerContext controllerContext);
    void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values);
}

SessionStateTempDataProvider这个是ITempDataProvider的默认接口,另外还有一个新增到MVCFutures里面的CookieTempDataProvider。

为什么说增强了可测试性呢?简单地讲,抽象出了接口就增强了易测性,这样外部就可以模拟这个接口做很多的事情了。

7、Action的几个调用方法的增强,主要都是些辅助方法,自己实现也不会有难度。

这里列一下官方提到的几个名字,个人觉得用途不是很大。(我是指对外部)

方法名

注释

GetFiltersForActionMethod

从action方法上返回各种Filters,想过去应该也知道用反射

InvokeActionResultWithFilters

连同所有的ActionFilter一起把Action都执行了。(跟名字是一个意思,其中的反序是很有意思的!)

InvokeAuthorizationFilters

调用AuthorizationFilters

InvokeExceptionFilters

调用ExceptionFilters

8、对ViewDataDictionary的一些小改变,主要体现在索引器上!

其实也就是在里面使用了TryGetValue(key, out value);以保证不会抛出异常。所以官方自己也不好意思说是进步,只好说是“a minor change”。

另外还增加了一个Eval的重载,多了一个format的参数。

9、ViewEngine的改进

  • 一个是增加对全局view engine的注册,目标就是让选择哪个view的职责从Controller中剥离出来。
  • 二是向IViewEngine增加FindPartialView接口。
         public interface IViewEngine {
              ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName);

         设计它是为了和Html.RenderPartial合作。

10、Helper的方法改进

  • 上一点讲到的Html.RenderPartial就是为了输出部分视图。类似截获一个页面的一部分,将其输出一样。
  • 还有就是增加一项不可选的默认项,比如说“请选择”这样的可选参数。
  • 然后就是AjaxHelper和HtmlHelper的方法都改成扩展方法了。也更新了所在的程序集:

<add namespace="System.Web.Mvc.Ajax"/>

<add namespace="System.Web.Mvc.Html"/>

  • 增加了RadioButton and TextArea两个控件。
  • 为了避免调用不明确,像Html.Hidden(“name”,123)这样的123则不是数字,而是object。

11、Controller和Filter的改进

  • 增加一个数组作为action方法的参数。
  • 从action filter context对象中移除了ActionMethod属性。
  • 增加ModelBinder,原本只能对一些简单类型如string int等进行处理,现在能对复杂的对象比如Duck这样的复杂类型进行处理了,这个进步还是很显著的。
  • 增加IActionInvoker接口,降低了耦合度。
  • 为Controller类增加UpdateModel方法,更新后的Model存放在ModelState里面,也可以从ViewData.ModelState中取,二者是同源的。
  • 对HandleErrorAttribute进行一些改变,直接返回状态码为500的错误。但是增加了以下代码用于允许自定义错误的属性,是否允许。以下代码将在最终抛出错误之前,至于如何使用,大家一看便知:

// If custom errors are disabled, we need to let the normal ASP.NET exception handler // execute so that the user can see useful debugging information. if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) { return; }

这个特征对调试是非常有效的。详细情况请参考《HttpContext.IsCustomErrorEnabled - One of ASP.NET's hidden gems

  • 增加了AcceptVerbsAttribute,就是可以指定HTTP method的类型,只有在类型匹配的时候才允许执行相应的controller,比如说你指定了POST,那么在GET的时候,是无法接触到相应的controller的。因此这个属性通常被和ActionNameAttribute一起使用,因为从方法重载的角度讲,是不允许签名相同的,但是经常会有要求重载签名不同,这样用ActionName就可以指定相同的名字,这个做法已经在.NET的各个框架中广泛应用了。再配以不同的AcceptVerbs则可以匹配各种不同的AcceptVerbs的情况以实现不同的效果。
  • ActionNameAttribute也是新增的。

另外一些对之前版本的已知问题的改变以及一些细节上的变化就不在此赘述了,多谈无益。

如果您要从preview3更新项目到beta,则需要做一些改变,这些改变也可以很方便地在文档中查阅,这里也不提了,毕竟受众较小。

那么从Preview5到Beta版的改进有哪些呢?

  • 对最终用户友好的验证消息。
  • 将CompositeViewEngine重命名为AutoViewEngine。
  • 为Controller类增加了一个Url属性,但注意它的类型不是string的,而是UrlHelper的。
  • 增加了ActionNameSelectorAttribute抽象基类。ActionNameAttribute就是继承自它的,因此您也可以扩展相应的类来满足自定义的塞选。
  • 增加了ReleaseView,这对资源清理是有益的。
  • 为了跟ReleaseView的方法命名规则统一,ControllerBuilder的DisposeController被重命名为ReleaseController。
  • 上面的第10点,一堆的方法从HtmlHelper中移出来变成扩展方法了。目的就在允许你实现自己的Extensions来扩展那些类似的方法,也可以增加你自己的一些方法。
  • 在DefaultModelBinder中用ModelBindingContext来代替传递Model复杂对象本身。
    public virtual ModelBinderResult BindModel(ModelBindingContext bindingContext)
  • 原来AcceptVerbsAttribute只允许使用字符串来传递指定的接收Verbs,比如AcceptVerbs(“GET”),现在增加了一个接受HttpVerbs枚举的重载,这样做显然更加优雅。而且可以用或运算符(|)来标识。但是原来的方式仍然允许,以备超出枚举范围的情况可以用。
  • default project template的改变
  • 如果有请求同时匹配两个ActionMethod,那么将抛出异常,但是现在将优先选择使用了ActionMethodSelectorAttribute的ActionMethod。
  • 上文第7点的最后一行,增加了ViewDataDictionary.Eval的一个重载。
  • ViewContext的ViewName属性也被删除了。
  • 作为ModelBinder体系的一部分,增加了IValueProvider接口以及DefaultValueProvider类。

之后就是一些BUG的Fix,也就没有解读的必要了。

罗列了这么多内容,其实在官方的文档中都能找得到,我增加了一些自己的理解以及在代码中的一些细节。阅读本文需要具备一定的MVC的知识,最好有了解过源码的各个模块的工作方式。这样对这些细节将会有比较深刻的认识。

posted on 2008-11-03 01:46  volnet(可以叫我大V)  阅读(768)  评论(0编辑  收藏  举报

使用Live Messenger联系我
关闭