Asp.Net MVC<八>:View的呈现

  1. ActionResult
  2. ViewResult和ViewEngine
    1. IViewEngine
    2. ViewResult
    3. ViewResultBase
  3. View的编译原理
    1. View程序集
    2. BuildManager
    3. WebViewPage的继承树
      1. 由.cshtml文件编译后产生的类文件
      2. WebPageExecutingBase
      3. WebPageRenderingBase
      4. WebPageBase
      5. WebViewPage
      6. WebViewPage
    4. View的呈现
      1. IView
      2. RazorView 实现
  4. 以IoC的方式激活View
  5. 扩展
    1. 扩展WebViewPage
    2. 扩展RazorViewEngine
  6.  

1、 ActionResult

原则上任何类型的响应都可以利用当前的HttpResponse来完成。但是MVC中我们一般将针对请求的响应实现在一个ActionResult对象中。

1
2
3
4
5
6
public abstract class ActionResult
{
    protected ActionResult();
 
    public abstract void ExecuteResult(ControllerContext context);
} 

 

2、 ViewResult和ViewEngine

2.1、 IViewEngine

viewResult通过ViewEngine实现对View的获取、激活和呈现。

1
2
3
4
5
6
7
8
public interface IViewEngine
{
    ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache);
 
    ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache);
 
    void ReleaseView(ControllerContext controllerContext, IView view);
}

 现有两种实现:WebFormViewEngine(.aspx,.ascx),RazorViewEngine(.cshtml/vbhtml)

1
2
3
4
5
6
7
8
public void Index()
{
    ViewEngineResult result = ViewEngines.Engines.FindView(ControllerContext, "NonExistView", null);
    foreach (var item in result.SearchedLocations)
    {
        Response.Write(item + "<br/>");
    }
}

  

因为WebFormViewEngine排在RazorViewEngine之前,所以前者被优先使用。可以用 ViewEngines.Engines.RemoveAt(0);来移除对WebFormViewEngine的调用。

2.2、 ViewResult

1
2
3
4
5
6
public class ViewResult : ViewResultBase
{
    public string MasterName { get; set; }
 
    protected override ViewEngineResult FindView(ControllerContext context);
}

2.3、 ViewResultBase 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public abstract class ViewResultBase: ActionResult
{
    public object Model { get; }
 
    //     临时数据。
    public TempDataDictionary TempData { get; set; }
 
    //     视图。
    public IView View { get; set; }
 
    //     视图包
    public dynamic ViewBag { get; }
 
    //     视图数据。
    public ViewDataDictionary ViewData { get; set; }
 
    //     视图引擎的集合。
    public ViewEngineCollection ViewEngineCollection { get; set; }
 
    //     视图的名称。
    public string ViewName { get; set; }
 
    //     视图引擎。
    protected abstract ViewEngineResult FindView(ControllerContext context);
    public override void ExecuteResult(ControllerContext context)
    {
        if (string.IsNullOrEmpty(this.ViewName))
        {
            this.ViewName = context.RouteData.GetRequiredString("action");
        }
 
        ViewEngineResult result = null;
        if(this.View == null)
        {
            result = this.FindView(context);
            this.View = result.View;
        }
 
        TextWriter output = context.HttpContext.Response.Output;
        ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, output);
        this.View.Render(viewContext, output);
 
        if(result != null)
        {
            result.ViewEngine.ReleaseView(context, this.View);
        }
    }
}

  抽象类Controller中的几个重载方法

3、  View的编译原理

 Asp.net mvc默认情况下采用动态编译的方式对View文件实施编译。当我们在部署的时候,需要对.cshtml或.vbhtml文件进行打包。

针对某个文件的第一次访问会触发针对它的编译,一个View会被编译成一个具体的类型。View文件的每一次修改都会导致再一次编译。和.aspx页面一样的编译方式,默认是以目录为单位的,也就是同一个目录下的多个View被编译到同一个程序集中。

3.1、 View程序集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class HtmlHelperExtensions
{
    public static MvcHtmlString ListViewAssemblies(this HtmlHelper helper)
    {
        TagBuilder ul = new TagBuilder("ul");
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName.StartsWith("App_Web_")))
        {
            TagBuilder li = new TagBuilder("li");
            li.InnerHtml = assembly.FullName;
            ul.InnerHtml += li.ToString();
        }
        return new MvcHtmlString(ul.ToString());
    }
}

View:  

1
2
3
<div>当前View类型:@this.GetType().AssemblyQualifiedName</div>
<div>当前加载的View程序集:</div>
@Html.ListViewAssemblies()

页面展示: 

 

 

3.2、 BuildManager

Response.Write(BuildManager.GetCompiledType("~/Views/Bar/Action1.cshtml") + "<br/>");
Response.Write(BuildManager.GetCompiledType("~/Views/Bar/Action2.cshtml") + "<br/>");

Response.Write(BuildManager.TargetFramework.FullName+ "<br/>");
Response.Write(BuildManager.GetCompiledCustomString("~/Views/Foo/Action1.cshtml") + "<br/>");
Response.Write(BuildManager.GetCompiledAssembly("~/Views/Foo/Action1.cshtml").Location + "<br/>");

页面展示:

3.3、 WebViewPage的继承树

3.3.1、 由.cshtml文件编译后产生的类文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
namespace ASP
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Web;
    using System.Web.Helpers;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.WebPages;
    using System.Web.Mvc;
    using System.Web.Mvc.Ajax;
    using System.Web.Mvc.Html;
    using System.Web.Optimization;
    using System.Web.Routing;
    using MvcApp;
 
 
    public class _Page_Views_Foo_Action1_cshtml : System.Web.Mvc.WebViewPage<dynamic>
    {
        protected ASP.global_asax ApplicationInstance
        {
            get
            {
                return ((ASP.global_asax)(Context.ApplicationInstance));
            }
        }
 
        public override void Execute()
        {
            BeginContext("~/Views/Foo/Action1.cshtml", 0, 14, true);
            WriteLiteral("<div>当前View类型:");
            EndContext("~/Views/Foo/Action1.cshtml", 0, 14, true);
            BeginContext("~/Views/Foo/Action1.cshtml", 15, 36, false);
            Write(this.GetType().AssemblyQualifiedName);
            EndContext("~/Views/Foo/Action1.cshtml", 15, 36, false);
            BeginContext("~/Views/Foo/Action1.cshtml", 51, 34, true);
            WriteLiteral("</div>\r\n<div>当前加载的View程序集:</div>\r\n");
            EndContext("~/Views/Foo/Action1.cshtml", 51, 34, true);
            BeginContext("~/Views/Foo/Action1.cshtml", 86, 25, false);
 
            Write(Html.ListViewAssemblies());
            EndContext("~/Views/Foo/Action1.cshtml", 86, 25, false);
            BeginContext("~/Views/Foo/Action1.cshtml", 111, 2, true);
            WriteLiteral("\r\n");
            EndContext("~/Views/Foo/Action1.cshtml", 111, 2, true);
        }
    }
}

 View编译后的生成的类型是WebViewPage<TModel>的子类,WebViewPage<TModel>是WebViewPage的子类,泛型TModel是View的Model类型。

3.3.2、 WebPageExecutingBase

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public abstract class WebPageExecutingBase
{
    public virtual dynamic App { get; }
    public virtual HttpApplicationStateBase AppState { get; }
    public virtual HttpContextBase Context { get; set; }
    public virtual string VirtualPath { get; set; }
    public virtual IVirtualPathFactory VirtualPathFactory { get; set; }
 
    public abstract void Execute();
    public virtual string Href(string path, params object[] pathParts);
    public virtual string NormalizePath(string path);
    protected internal virtual TextWriter GetOutputWriter();
    protected internal virtual string NormalizeLayoutPagePath(string layoutPagePath);
 
    //动态内容
    public abstract void Write(object value);
    public abstract void Write(HelperResult result);
    public static void WriteTo(TextWriter writer, object content);
    public static void WriteTo(TextWriter writer, HelperResult content);
    //静态内容
    public abstract void WriteLiteral(object value);
    public static void WriteLiteralTo(TextWriter writer, object content);
 
    public virtual void WriteAttribute(string name, PositionTagged<string> prefix, PositionTagged<string> suffix, params AttributeValue[] values);
    public virtual void WriteAttributeTo(TextWriter writer, string name, PositionTagged<string> prefix, PositionTagged<string> suffix, params AttributeValue[] values);
    protected internal virtual void WriteAttributeTo(string pageVirtualPath, TextWriter writer, string name, PositionTagged<string> prefix, PositionTagged<string> suffix, params AttributeValue[] values);
 
    protected internal void BeginContext(int startPosition, int length, bool isLiteral);
    protected internal void BeginContext(string virtualPath, int startPosition, int length, bool isLiteral);
    protected internal void BeginContext(TextWriter writer, int startPosition, int length, bool isLiteral);
    protected internal void BeginContext(TextWriter writer, string virtualPath, int startPosition, int length, bool isLiteral);
    protected internal void EndContext(int startPosition, int length, bool isLiteral);
    protected internal void EndContext(string virtualPath, int startPosition, int length, bool isLiteral);
    protected internal void EndContext(TextWriter writer, int startPosition, int length, bool isLiteral);
    protected internal void EndContext(TextWriter writer, string virtualPath, int startPosition, int length, bool isLiteral);
}

  

3.3.3、 WebPageRenderingBase 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public abstract class WebPageRenderingBase : WebPageExecutingBase, ITemplateFile
{
    public virtual Cache Cache { get; }
    public string Culture { get; set; }
    public virtual bool IsAjax { get; }
    public virtual bool IsPost { get; }
    public abstract string Layout { get; set; }
    //     An object that contains page data.
    public abstract dynamic Page { get; }
    public abstract IDictionary<object, dynamic> PageData { get; }
    public WebPageContext PageContext { get; }
    public ProfileBase Profile { get; }
    public virtual HttpRequestBase Request { get; }
    public virtual HttpResponseBase Response { get; }
    public virtual HttpServerUtilityBase Server { get; }
    public virtual HttpSessionStateBase Session { get; }
    public virtual TemplateFileInfo TemplateInfo { get; }
    public string UICulture { get; set; }
    public virtual IList<string> UrlData { get; }
    public virtual IPrincipal User { get; internal set; }
    protected internal IDisplayMode DisplayMode { get; }
 
    public abstract void ExecutePageHierarchy();
    public abstract HelperResult RenderPage(string path, params object[] data);
}

  ExecutePageHierarchy负责整个页面内容的输出,

     View自身内容通过重写Execute方法来输出。

3.3.4、 WebPageBase 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public abstract class WebPageBase : WebPageRenderingBase
{
    //其他成员……  
 
    //     Gets or sets the path of a layout page.
    public override string Layout { get; set; }
    public TextWriter Output { get; }  
    //     Returns the text writer instance that is used to render the page.
    protected internal override TextWriter GetOutputWriter();
     
    //     Gets the stack of System.IO.TextWriter objects for the current page context.
    public Stack<TextWriter> OutputStack { get; }
    //     Returns and removes the context from the top of the System.Web.WebPages.WebPageBase.OutputStack
    //     instance.
    public void PopContext();
    //     Inserts the specified context at the top of the System.Web.WebPages.WebPageBase.OutputStack
    //     instance.
    public void PushContext(WebPageContext pageContext, TextWriter writer);
 
    //     Executes the code in a set of dependent web pages.
    public override void ExecutePageHierarchy();
    //     Executes the code in a set of dependent web pages by using the specified parameters.
    public void ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer);
    //     Executes the code in a set of dependent web pages by using the specified context,
    //     writer, and start page.
    public void ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage);
 
    //     Returns a value that indicates whether the specified section is defined in the
    //     page.
    public bool IsSectionDefined(string name);
    //     Called by content pages to create named content sections.
    public void DefineSection(string name, SectionWriter action);
     
    //     In layout pages, renders the portion of a content page that is not within a named
    //     section.
    public HelperResult RenderBody();
    //     Renders the content of one page within another page.
    public override HelperResult RenderPage(string path, params object[] data);
    //     In layout pages, renders the content of a named section.
    public HelperResult RenderSection(string name);
    //     In layout pages, renders the content of a named section and specifies whether
    //     the section is required.
    public HelperResult RenderSection(string name, bool required);
 
    //     Writes the specified object as an HTML-encoded string.
    public override void Write(object value);
    //     Writes the specified System.Web.WebPages.HelperResult object as an HTML-encoded
    //     string.
    public override void Write(HelperResult result);
    //     Writes the specified object without HTML-encoding it first.
    public override void WriteLiteral(object value);
}

  WebPageBase 实现了抽象方法ExecutePageHierarchy,定义了额外的两个ExecutePageHierarchy方法重载,参数startPage表示定义在“_ViewStart.cshtml”文件的开始页面。

    最初呈现的内容来源于3个部分:布局文件,开始页面和View自身的内容。完整页面内容的呈现通过调用ExecutePageHierarchy方法来完成。

    WebPageBase 实现了抽象方法Write/WriteLiteral和抽象属性 Layout。

    定义了在布局文件上输出Section的方法。

3.3.5、 WebViewPage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public abstract class WebViewPage : WebPageBase, IViewDataContainer, IViewStartPageChild
{
    //     The System.Web.Mvc.AjaxHelper object that is used to render HTML using Ajax.
    public AjaxHelper<object> Ajax { get; set; }
 
    //     The System.Web.HttpContext object that is associated with the page.
    public override HttpContextBase Context { get; set; }
 
    //     The System.Web.Mvc.HtmlHelper object that is used to render HTML elements.
    public HtmlHelper<object> Html { get; set; }
     
    public object Model { get; }
    public TempDataDictionary TempData { get; }
    public UrlHelper Url { get; set; }
    public dynamic ViewBag { get; }
    public ViewContext ViewContext { get; set; }
    public ViewDataDictionary ViewData { get; set; }
 
    //     Runs the page hierarchy for the ASP.NET Razor execution pipeline.
    public override void ExecutePageHierarchy();
 
    //     Initializes the System.Web.Mvc.AjaxHelper, System.Web.Mvc.HtmlHelper,
    //     and System.Web.Mvc.UrlHelper classes.
    public virtual void InitHelpers();
 
    //     Sets the view context and view data for the page.
    protected override void ConfigurePage(WebPageBase parentPage);
 
    protected virtual void SetViewData(ViewDataDictionary viewData);
}

 

  

3.3.6、 WebViewPage<TModel>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class WebViewPage<TModel> : WebViewPage
{
    public AjaxHelper<TModel> Ajax { get; set; }
 
    public HtmlHelper<TModel> Html { get; set; }
 
    public TModel Model { get; }
 
    public ViewDataDictionary<TModel> ViewData { get; set; }
 
    public override void InitHelpers();
 
    protected override void SetViewData(ViewDataDictionary viewData);
}

  提供针对泛型参数TModel的属性Ajax, Html, Model, ViewData, 而初始化它们的InitHelpers和SetViewData方法也被重写

3.4、  View的呈现

3.4.1、 IView

对应View引擎来说,View通过IView来表示

1
2
3
4
public interface IView
{
    void Render(ViewContext viewContext, TextWriter writer);
}

View的呈现体现在对WebViewPage对象的激活上。

 在Asp.net mvc 中Razor引擎下的View通过RazorView对象来表示,WebForm引擎的View则通过WebFormView对象表示,二者都继承自BuildManagerCompiledView。

3.4.2、 RazorView 实现

BuildManagerCompiledView 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public abstract class BuildManagerCompiledView : IView
{
    internal IViewPageActivator ViewPageActivator;
    private IBuildManager _buildManager;
    private ControllerContext _controllerContext;
    internal IBuildManager BuildManager
    {
        get
        {
            if (this._buildManager == null)
            {
                this._buildManager = new BuildManagerWrapper();
            }
            return this._buildManager;
        }
        set
        {
            this._buildManager = value;
        }
    }
    public string ViewPath { get; protected set; }
 
    protected BuildManagerCompiledView(ControllerContext controllerContext, string viewPath) : this(controllerContext, viewPath, null)
    {
    }
 
    protected BuildManagerCompiledView(ControllerContext controllerContext, string viewPath, IViewPageActivator viewPageActivator) : this(controllerContext, viewPath, viewPageActivator, null)
    {
    }
    internal BuildManagerCompiledView(ControllerContext controllerContext, string viewPath, IViewPageActivator viewPageActivator, IDependencyResolver dependencyResolver)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }
        if (string.IsNullOrEmpty(viewPath))
        {
            throw new ArgumentException(MvcResources.Common_NullOrEmpty, "viewPath");
        }
        this._controllerContext = controllerContext;
        this.ViewPath = viewPath;
        this.ViewPageActivator = (viewPageActivator ?? new BuildManagerViewEngine.DefaultViewPageActivator(dependencyResolver));
    }
 
    public virtual void Render(ViewContext viewContext, TextWriter writer)
    {
        if (viewContext == null)
        {
            throw new ArgumentNullException("viewContext");
        }
        object obj = null;
        Type compiledType = this.BuildManager.GetCompiledType(this.ViewPath);
        if (compiledType != null)
        {
            obj = this.ViewPageActivator.Create(this._controllerContext, compiledType);
        }
        if (obj == null)
        {
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.CshtmlView_ViewCouldNotBeCreated, new object[]
            {
            this.ViewPath
            }));
        }
        this.RenderView(viewContext, writer, obj);
    }
 
    protected abstract void RenderView(ViewContext viewContext, TextWriter writer, object instance);
}

 RazorView 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/// <summary>Represents the class used to create views that have Razor syntax.</summary>
public class RazorView : BuildManagerCompiledView
{
    public string LayoutPath { get; private set; }
    public bool RunViewStartPages { get; private set; }
    internal StartPageLookupDelegate StartPageLookup { get; set; }
    internal IVirtualPathFactory VirtualPathFactory { get; set; }
    internal DisplayModeProvider DisplayModeProvider { get; set; }
    public IEnumerable<string> ViewStartFileExtensions { get; private set; }
    public RazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions) : this(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions, null)
    {
    }
    /// <summary>Initializes a new instance of the <see cref="T:System.Web.Mvc.RazorView" /> class using the view page activator.</summary>
    /// <param name="controllerContext">The controller context.</param>
    /// <param name="viewPath">The view path.</param>
    /// <param name="layoutPath">The layout or master page.</param>
    /// <param name="runViewStartPages">A value that indicates whether view start files should be executed before the view.</param>
    /// <param name="viewStartFileExtensions">The set of extensions that will be used when looking up view start files.</param>
    /// <param name="viewPageActivator">The view page activator.</param>
    public RazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions, IViewPageActivator viewPageActivator) : base(controllerContext, viewPath, viewPageActivator)
    {
        this.LayoutPath = (layoutPath ?? string.Empty);
        this.RunViewStartPages = runViewStartPages;
        this.StartPageLookup = new StartPageLookupDelegate(StartPage.GetStartPage);
        this.ViewStartFileExtensions = (viewStartFileExtensions ?? Enumerable.Empty<string>());
    }
    /// <summary>Renders the specified view context by using the specified writer and <see cref="T:System.Web.Mvc.WebViewPage" /> instance.</summary>
    /// <param name="viewContext">The view context.</param>
    /// <param name="writer">The writer that is used to render the view to the response.</param>
    /// <param name="instance">The <see cref="T:System.Web.Mvc.WebViewPage" /> instance.</param>
    protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
    {
        if (writer == null)
        {
            throw new ArgumentNullException("writer");
        }
        WebViewPage webViewPage = instance as WebViewPage;
        if (webViewPage == null)
        {
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.CshtmlView_WrongViewBase, new object[]
            {
                base.ViewPath
            }));
        }
        webViewPage.OverridenLayoutPath = this.LayoutPath;
        webViewPage.set_VirtualPath(base.ViewPath);
        webViewPage.ViewContext = viewContext;
        webViewPage.ViewData = viewContext.ViewData;
        webViewPage.InitHelpers();
        if (this.VirtualPathFactory != null)
        {
            webViewPage.set_VirtualPathFactory(this.VirtualPathFactory);
        }
        if (this.DisplayModeProvider != null)
        {
            webViewPage.set_DisplayModeProvider(this.DisplayModeProvider);
        }
        WebPageRenderingBase webPageRenderingBase = null;
        if (this.RunViewStartPages)
        {
            webPageRenderingBase = this.StartPageLookup(webViewPage, RazorViewEngine.ViewStartFileName, this.ViewStartFileExtensions);
        }
        webViewPage.ExecutePageHierarchy(new WebPageContext(viewContext.HttpContext, null, null), writer, webPageRenderingBase);
    }
}

4、 以IoC的方式激活View

 RazorView 的构造函数中有用到IViewPageActivator,IViewPageActivator旨在View对象的激活。当没有指定一个具体的ViewPageActivator时,默认采用 DefaultViewPageActivator对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
internal class DefaultViewPageActivator : IViewPageActivator
{
    private Func<IDependencyResolver> _resolverThunk;
    public DefaultViewPageActivator() : this(null)
    {
    }
    public DefaultViewPageActivator(IDependencyResolver resolver)
    {
        if (resolver == null)
        {
            this._resolverThunk = (() => DependencyResolver.Current);
            return;
        }
        this._resolverThunk = (() => resolver);
    }
    public object Create(ControllerContext controllerContext, Type type)
    {
        object result;
        try
        {
            result = (this._resolverThunk().GetService(type) ?? Activator.CreateInstance(type));
        }
        catch (MissingMethodException originalException)
        {
            MissingMethodException ex = TypeHelpers.EnsureDebuggableException(originalException, type.FullName);
            if (ex != null)
            {
                throw ex;
            }
            throw;
        }
        return result;
    }
}

5、 扩展

5.1、 扩展WebViewPage

 IDependencyResolver 是Asp.net mvc提供的IoC接入口,所以这里可以介入到具体某个WebViewPage<TModel>类型的实例化。

 

下面的例子是向View中注入一个属性,用于在页面中便捷地读取资源文件信息。

1
2
3
4
5
public abstract class LocalizableViewPage<TModel> : WebViewPage<TModel>
{
    [Inject]
    public ResourceReader ResourceReader { get; set; }
}
1
2
3
4
5
6
7
public class DefaultResourceReader : ResourceReader
{
    public override string GetString(string name)
    {
        return Resources.ResourceManager.GetString(name);
    }
}

在View 顶部 添加命令 @inherits LocalizableViewPage<>

1
2
3
4
5
6
7
8
9
@inherits LocalizableViewPage<object>
<html>
<head>
    <title></title>
</head>
<body>
    <h2>@ResourceReader.GetString("HelloWorld")</h2>
</body>
</html>

或者修改View文件夹下的Web.config配置

1
2
3
4
5
6
7
8
9
10
11
12
13
<system.web.webPages.razor>
  <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  <pages pageBaseType="LocalizableViewPage">
    <namespaces>
      <add namespace="System.Web.Mvc" />
      <add namespace="System.Web.Mvc.Ajax" />
      <add namespace="System.Web.Mvc.Html" />
      <add namespace="System.Web.Optimization"/>
      <add namespace="System.Web.Routing" />
      <add namespace="MvcApp" />
    </namespaces>
  </pages>
</system.web.webPages.razor>

5.2、 扩展RazorViewEngine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class MyViewEngine : RazorViewEngine
{
    public MyViewEngine()
    {
        ViewLocationFormats = new[]
        {
            "~/Views/{1}/{0}.cshtml",
            "~/Views/Shared/{0}.cshtml",
            "~/Views/Areas/{1}/{0}.cshtml"
        };
        AreaViewLocationFormats = new[]
        {
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml",
 
            "~/Areas/{2}/Views/Config/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/User/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Case/{1}/{0}.cshtml",
 
            "~/Areas/{2}/Views/Config/Shared/{0}.cshtml",
            "~/Areas/{2}/Views/User/Shared/{0}.cshtml",
            "~/Areas/{2}/Views/Case/Shared/{0}.cshtml"
        };
    }
 
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        return base.FindView(controllerContext, viewName, masterName, useCache);
    }
}
 
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MyViewEngine());

  

 

posted @   随心~  阅读(685)  评论(0编辑  收藏  举报
编辑推荐:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
阅读排行:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!

点击右上角即可分享
微信分享提示