ASP.NET MVC 3 RTM 更新(1)
一、路由(Routing)
路由功能最初整合在ASP.NET MVC(以下简称MVC)中,后来被独立出来形成了System.Web.Routing 3.5程序集。ASP.NET 4已经把Routing功能已经转移到了System.Web 4 程序集下作为基础服务的一部分。在使用Routing功能时,您已不再需要在web.config中注册Module,因为UrlRoutingModule已经集成进ASP.NET 4中了,就像FormsAuthenticationModule等Module一样(
在System.Web.Routing 3.5中,UrlRoutingModule通过处理PostResolveRequestCache和PostMapRequestHandler事件来配合设置请求处理程序(IHttpHandler),而在System.Web.Routing 4中,只处理了PostResolveRequestCache事件(PostMapRequestHandler事件也处理了,但什么都不做,但已标明过期)。
值得一提的是ASP.NET 4的HttpRequest新增加了一个RequestContext属性,其类型正是System.Web.Routing.RequestContext。该类封装了当前请求上下文以及RouteData。
增加了PageRouteHandler类以支持WebForm的路由功能,该类实现IRouteHandler接口。而在ASP.NET 2.0中,得自己实现类似的IRouteHandler。
为了更方便的添加该类型的路由规则,RouteCollection类中还新增加了四个MapPageRoute的重载方法。
简单演示一下:
1、新建一个基于.Net 4的Web Application。
2、新建Global.asa并修改Global.asa.cs的Application_Start方法
void Application_Start(object sender, EventArgs e)
{
// 以下两种方式都可以添加路由规则,显然MapPageRoute更方便、清晰一些
//RouteTable.Routes.Add("newRoute",new Route("TestRouting",new PageRouteHandler("~/TestRouting.aspx")));
RouteTable.Routes.MapPageRoute("newRoute"
, "RoutingTest"
, "~/RoutingTest.aspx");
}
3、新建Web窗体,命名为RoutingTest.aspx。在里面随便输入一些内容。
4、启动调试(F5),输入类似的网址:http://localhost:3232/RoutingTest
一切正常的话应该显示出您输入的内容。
二、IDependencyResolver和DependencyResolver
Ioc/DI(Inversion of Control / the Dependency Injection,控制反转/依赖注入)是实现系统解耦的一大利器。.Net平台可用的DI容器有Castle Windsor、StructureMap、Autofac 、Unity等。在MVC2中我们就可以很容易的使用这些容器,MVC3在DI方面又为我们做了什么呢?
需要清楚一点,MVC3对DI的支持并不是说它内置了类似于Autofac之类的DI容器。它只是内置了一种创建(获取)对象的默认“方式”(DefaultDependencyResolver),这种“方式”内部其中一个途径是通过Activator.CreateInstance(Type serviceType)来创建对象。更重要的是,它提供了一种API让我们可以改变这种方式。这使得我们可以使用Autofac之类的DI方式来替换。
下面我们从源码角度分析一下MVC3是如何实现这种机制的。
首先看看IDependencyResolver接口,该接口正是上面所说的创建(获取)对象的“方式”。接口有两个方法,GetService根据Type获取一个简单对象,GetServices根据Type获取一个集合对象。
public interface IDependencyResolver
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
DependencyResolver并不是IDependencyResolver接口的实现。
它有两个私有内联类DefaultDependencyResolver和DelegateBasedDependencyResolver,都是现实的IDependencyResolver接口;
一个DependencyResover型的私有变量_instance;
一个IDependencyResolver型的私有变量_current;
一个静态构造方法,方法内部创建一个DependencyResolver赋给_instance变量;
一个默认构造方法,方法内部创建一个DefaultDependencyResolver赋给_current变量;
两个只读的类型为IDependencyResolver的属性Current和InnerCurrent,这两个属性的get方法最终返回的是_instance变量——典型的单例模式;
三个InnerSetResolver重载方法和三个SetResolver重载方法。每个SetResolver只是简单的调用对应的InnerSetResolver方法。这些方法用于设置当前的IDependencyResolver对象,并将对象赋给_current变量。
当我们需要根据某种类型比如SomeClass创建相应的对象时,我们这样调用:DependencyResolver.Current.GetService(typeof(SomeType))。
当然,返回结合对象就这样调用DependencyResolver.Current.GetServices(typeof(SomeType))。
默认情况下我们使用的是DefaultDependencyResolver对象,在该对象的GetService方法内部,通过调用Activator.CreateInstance(typeof(SomeType))来创建对象,而GetServices方法返回的是numerable.Empty<object>()生成的对象。
IDependencyResolver接口是创建(获取)对象的“方式”,而SetResolver方法等则是改变这种方式的API。下面简单分析一下这几个方法。
1、InnerSetResolver(IDependencyResolver resolver)
该方法接受一个IDependencyResolver型参数,方法内部直接将值赋给_current变量。
2、InnerSetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices)
该方法接受两个委托,第一个接受一个Type型参数返回object型对象,而第二个返回IEnumerable<object>型集合对象。
方法内部创建一个DelegateBasedDependencyResolver对象。调用DelegateBasedDependencyResolver.GetService(Type type)返回的
是getService(type)的执行结果。相应的,调用GetServices(Type type)返回的是getServices(type)的执行结果。
3、InnerSetResolver(object commonServiceLocator)
该方法接受一个object型参数,方法内部会通过反射的方式尝试获取方法名为"GetInstance"和"GetAllInstances",参数为Type型的两个方法;
接着检查方法的返回值是否分别是object型和IEnumeralbe<object>型,如果是创建一个DelegateBasedDependencyResolver对象,两个方法作为构造方法
参数传入,并将对象赋给_current变量。返回值的不匹配则抛出异常。
您可能需要CommonServiceLocator的资料:http://commonservicelocator.codeplex.com
另外,DependencyResolverExtensions类是IDependencyResolver接口的扩展方法,分别是相应方法的泛型实现。
public static class DependencyResolverExtensions
{
public static TService GetService<TService>(this IDependencyResolver resolver)
{
return (TService) resolver.GetService(typeof(TService));
}
public static IEnumerable<TService> GetServices<TService>(this IDependencyResolver resolver)
{
return resolver.GetServices(typeof(TService)).Cast<TService>();
}
}
IDependencyResolver接口的实现类中,通常采用外观模式。内部包含一个DI容器,当调用GetService或GetServices方法时,调用DI容器相应的方法。
路由功能最初整合在ASP.NET MVC(以下简称MVC)中,后来被独立出来形成了System.Web.Routing 3.5程序集。ASP.NET 4已经把Routing功能已经转移到了System.Web 4 程序集下作为基础服务的一部分。在使用Routing功能时,您已不再需要在web.config中注册Module,因为UrlRoutingModule已经集成进ASP.NET 4中了,就像FormsAuthenticationModule等Module一样(
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.config 的httpModules节点)。而ASP.NET MVC 3(以下简称MVC3)是基于ASP.NET 4的。
在System.Web.Routing 3.5中,UrlRoutingModule通过处理PostResolveRequestCache和PostMapRequestHandler事件来配合设置请求处理程序(IHttpHandler),而在System.Web.Routing 4中,只处理了PostResolveRequestCache事件(PostMapRequestHandler事件也处理了,但什么都不做,但已标明过期)。
值得一提的是ASP.NET 4的HttpRequest新增加了一个RequestContext属性,其类型正是System.Web.Routing.RequestContext。该类封装了当前请求上下文以及RouteData。
增加了PageRouteHandler类以支持WebForm的路由功能,该类实现IRouteHandler接口。而在ASP.NET 2.0中,得自己实现类似的IRouteHandler。
为了更方便的添加该类型的路由规则,RouteCollection类中还新增加了四个MapPageRoute的重载方法。
简单演示一下:
1、新建一个基于.Net 4的Web Application。
2、新建Global.asa并修改Global.asa.cs的Application_Start方法
void Application_Start(object sender, EventArgs e)
{
// 以下两种方式都可以添加路由规则,显然MapPageRoute更方便、清晰一些
//RouteTable.Routes.Add("newRoute",new Route("TestRouting",new PageRouteHandler("~/TestRouting.aspx")));
RouteTable.Routes.MapPageRoute("newRoute"
, "RoutingTest"
, "~/RoutingTest.aspx");
}
3、新建Web窗体,命名为RoutingTest.aspx。在里面随便输入一些内容。
4、启动调试(F5),输入类似的网址:http://localhost:3232/RoutingTest
一切正常的话应该显示出您输入的内容。
二、IDependencyResolver和DependencyResolver
Ioc/DI(Inversion of Control / the Dependency Injection,控制反转/依赖注入)是实现系统解耦的一大利器。.Net平台可用的DI容器有Castle Windsor、StructureMap、Autofac 、Unity等。在MVC2中我们就可以很容易的使用这些容器,MVC3在DI方面又为我们做了什么呢?
需要清楚一点,MVC3对DI的支持并不是说它内置了类似于Autofac之类的DI容器。它只是内置了一种创建(获取)对象的默认“方式”(DefaultDependencyResolver),这种“方式”内部其中一个途径是通过Activator.CreateInstance(Type serviceType)来创建对象。更重要的是,它提供了一种API让我们可以改变这种方式。这使得我们可以使用Autofac之类的DI方式来替换。
下面我们从源码角度分析一下MVC3是如何实现这种机制的。
首先看看IDependencyResolver接口,该接口正是上面所说的创建(获取)对象的“方式”。接口有两个方法,GetService根据Type获取一个简单对象,GetServices根据Type获取一个集合对象。
public interface IDependencyResolver
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
DependencyResolver并不是IDependencyResolver接口的实现。
它有两个私有内联类DefaultDependencyResolver和DelegateBasedDependencyResolver,都是现实的IDependencyResolver接口;
一个DependencyResover型的私有变量_instance;
一个IDependencyResolver型的私有变量_current;
一个静态构造方法,方法内部创建一个DependencyResolver赋给_instance变量;
一个默认构造方法,方法内部创建一个DefaultDependencyResolver赋给_current变量;
两个只读的类型为IDependencyResolver的属性Current和InnerCurrent,这两个属性的get方法最终返回的是_instance变量——典型的单例模式;
三个InnerSetResolver重载方法和三个SetResolver重载方法。每个SetResolver只是简单的调用对应的InnerSetResolver方法。这些方法用于设置当前的IDependencyResolver对象,并将对象赋给_current变量。
当我们需要根据某种类型比如SomeClass创建相应的对象时,我们这样调用:DependencyResolver.Current.GetService(typeof(SomeType))。
当然,返回结合对象就这样调用DependencyResolver.Current.GetServices(typeof(SomeType))。
默认情况下我们使用的是DefaultDependencyResolver对象,在该对象的GetService方法内部,通过调用Activator.CreateInstance(typeof(SomeType))来创建对象,而GetServices方法返回的是numerable.Empty<object>()生成的对象。
IDependencyResolver接口是创建(获取)对象的“方式”,而SetResolver方法等则是改变这种方式的API。下面简单分析一下这几个方法。
1、InnerSetResolver(IDependencyResolver resolver)
该方法接受一个IDependencyResolver型参数,方法内部直接将值赋给_current变量。
2、InnerSetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices)
该方法接受两个委托,第一个接受一个Type型参数返回object型对象,而第二个返回IEnumerable<object>型集合对象。
方法内部创建一个DelegateBasedDependencyResolver对象。调用DelegateBasedDependencyResolver.GetService(Type type)返回的
是getService(type)的执行结果。相应的,调用GetServices(Type type)返回的是getServices(type)的执行结果。
3、InnerSetResolver(object commonServiceLocator)
该方法接受一个object型参数,方法内部会通过反射的方式尝试获取方法名为"GetInstance"和"GetAllInstances",参数为Type型的两个方法;
接着检查方法的返回值是否分别是object型和IEnumeralbe<object>型,如果是创建一个DelegateBasedDependencyResolver对象,两个方法作为构造方法
参数传入,并将对象赋给_current变量。返回值的不匹配则抛出异常。
您可能需要CommonServiceLocator的资料:http://commonservicelocator.codeplex.com
另外,DependencyResolverExtensions类是IDependencyResolver接口的扩展方法,分别是相应方法的泛型实现。
public static class DependencyResolverExtensions
{
public static TService GetService<TService>(this IDependencyResolver resolver)
{
return (TService) resolver.GetService(typeof(TService));
}
public static IEnumerable<TService> GetServices<TService>(this IDependencyResolver resolver)
{
return resolver.GetServices(typeof(TService)).Cast<TService>();
}
}
IDependencyResolver接口的实现类中,通常采用外观模式。内部包含一个DI容器,当调用GetService或GetServices方法时,调用DI容器相应的方法。