ASP.NET MVC Razor介绍:IoC在View激活过程中的应用

  在《ASP.NET MVC Razor介绍:RazorView》 介绍BuildManagerCompiledView的时候,我们谈到默认使用的ViewPageActivator使用当前注册的 DependencyResolver来完成对目标View的激活,这意味着我们可以通过注册自定义DependencyResolver的方式实现基于 IoC的View激活。本篇文章中我们将演示如何通过自定义View的方式实现与IoC框架Ninject的集成。

  定义了一个具有如下定义的NinjectDependencyResolver,它具有一个IKernel类型的只读属性Kernel,该属性在构造函 数中被初始化为一个StandardKernel对象。对于实现的GetService和GetServices方法,我们直接调用Kernel的 TryGet和GetAll返回指定类型的实例和实例列表。为了方便进行类型映射,我们定义了泛型的Register<TFrom,TTo> 方法。

 public class NinjectDependencyResolver : IDependencyResolver
 {
     public IKernel Kernel { get; private set; }
     public NinjectDependencyResolver()
     {
         this.Kernel = new StandardKernel();
     }
     public void Register<TFrom, TTo>() where TTo: TFrom
     {
         this.Kernel.Bind<TFrom>().To<TTo>();
     }
     public object GetService(Type serviceType)
     {
         return this.Kernel.TryGet(serviceType);
     }
     public IEnumerable<object> GetServices(Type serviceType)
     {
         return this.Kernel.GetAll(serviceType);
     }
 }

  我们演示的是一个针对多语言支持的场景,为了让View上输出的一些内容随着当前线程的UICulture而动态地变化,我们在一个ASP.NET MVC应用中定义如下一个读取资源内容抽象类ResourceReader。这里资源是一个宽泛的概念,并不对存储方式作强制的约束,我们可以使用资源文 件也可以使用数据库来存储资源内容。简单起见,ResourceReader仅仅定义了一个唯一GetString方法获取指定名称的字符串。

 public abstract class ResourceReader
 {
     public abstract string GetString(string name);
 }

  我们默认采用资源文件来定义数据源,为此我们在项目中添加了两个资源文件Resoures.resx(语言文化中性)和Resources.zh.resx(中文),并在资源文件中添加了如下图所示的资源项(HelloWorld)。

ASP.NET MVC Razor介绍:IoC在View激活过程中的应用

  然后我们创建如下一个默认的DefaultResourceReader,它默认读取我们添加的资源文件来获取GetString方法返回的字符串(静态类型Resources是添加资源文件自动创建的类型)。

 public class DefaultResourceReader : ResourceReader
 {
     public override string GetString(string name)
     {
         return Resources.ResourceManager.GetString(name);
     }
 }

  为了让ResourceManager能够应用到所有的View中,我们为整个应用的View创建了如下一个基类 LocalizableViewPage<TModel>。该类型是WebViewPage<TModel>的子类,它具有一个 类型为ResourceManager的属性ResourceManager。由于该属性上应用了Ninject.InjectAttribute特性, 意味着该属性会以“属性注入”的方式被自动初始化。

 public abstract class LocalizableViewPage<TModel>: WebViewPage<TModel>
 {
     [Inject]
     public ResourceReader ResourceReader { get;  set; }
 }

  接下来我们定义了如下一个简单的HomeController,其默认的Action方法Index中直接将对应的View呈现出来。

 public class HomeController : Controller
 {
     public ActionResult Index()
     {
         return View();
     }
 }

  如下所示的是Action方法Index对应View的定义,我们使用@inherits指令让动态编译生成的View类型继承自我们自定义的基类 LocalizableViewPage<object>。我们直接调用ResourceReader属性的GetString方法提取名称 为“HelloWorld”的字符串资源内容显示出来。

 @inherits LocalizableViewPage<object>
 <html>
     <head>
         <title></title>
     </head>
     <body>
         <h2>@ResourceReader.GetString("HelloWorld")</h2>
     </body>
 </html>

  我们采用基于URL的语言文化决定机制,即将语言文化的代码置于请求URL中来决定希望采用的语言。为此我们在自动生成的RouteConfig类型中注册了如下一个URL模板为“{culture}/{controller}/{action}”的路由对象。

 public class RouteConfig
 {
     public static void RegisterRoutes(RouteCollection routes)
     {
         //其他操作
         routes.MapRoute(
             name        : "Default",
             url         : "{culture}/{controller}/{action}",
             defaults    : new {
             culture        = "zh-CN",
             controller     = "Home",
             action         = "Index"}
         );
     }
 }

  我们自定义的DefaultResourceReader能够根据当前线程的UICulture选择对应的资源文件,那么我们只需要根据请求地址指 示的语言文件对当前线程的语言文件进行相应的设置即可。于是我们在Global.asax定义了如下一个 Application_BeginRequest方法使HttpApplication的BeginRequest事件触发的时候从请求地址中提取语言 文化代码,然后对当前线程的语言文化进行相应的设置。除此之外,针对NinjectDependencyResolver的注册和 ResourceReader与Default ResourceReader之间的映射关系定义在Application_Start方法中。

 public class MvcApplication : System.Web.HttpApplication
 {
     protected void Application_Start()
     {
         //其他操作
         NinjectDependencyResolver dependencyResovler = new NinjectDependencyResolver();
         dependencyResovler.Register<ResourceReader, DefaultResourceReader>();
         DependencyResolver.SetResolver(dependencyResovler);
     }
  
     protected void Application_BeginRequest()
     { 
         HttpContextBase contextWrapper = new HttpContextWrapper(HttpContext.Current);
         string culture = RouteTable.Routes.GetRouteData(contextWrapper).Values["culture"] as string;
         if (!string.IsNullOrEmpty(culture))
         {
             try
             {
                 CultureInfo cultureInfo                 = new CultureInfo(culture);
                 Thread.CurrentThread.CurrentCulture     = cultureInfo;
                 Thread.CurrentThread.CurrentUICulture   = cultureInfo;
             }
             catch {}
         }
     }
 }

  现在运行我们的程序,并通过地址指定采用的语言文化,我们可以发现呈选出来的内容与你指定的语言文化是一致的,具体的输出效果如下图所示。

ASP.NET MVC Razor介绍:IoC在View激活过程中的应用

作者:Artech
出处:http://artech.cnblogs.com/

评论(0)网络
阅读(75)喜欢(0)不喜欢(0)asp.net-mvc