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


    ActionResult

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

    public abstract class ActionResult
    {
        protected ActionResult();
    
        public abstract void ExecuteResult(ControllerContext context);
    } 

    ViewResult和ViewEngine

    IViewEngine

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

    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)

    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的调用。

    ViewResult

    public class ViewResult : ViewResultBase
    {
        public string MasterName { get; set; }
    
        protected override ViewEngineResult FindView(ControllerContext context);
    }
    

    ViewResultBase 

    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中的几个重载方法

     View的编译原理

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

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

    View程序集

    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:  

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

    页面展示: 

     

    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/>");

    页面展示:

    WebViewPage的继承树

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

    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>
    <div>当前加载的View程序集:</div>
    ");
                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("
    ");
                EndContext("~/Views/Foo/Action1.cshtml", 111, 2, true);
            }
        }
    }
    

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

    WebPageExecutingBase

    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);
    }
    

      

    WebPageRenderingBase 

    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方法来输出。

    WebPageBase 

    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的方法。

    WebViewPage

    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);
    }
    

      

    WebViewPage<TModel>

    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方法也被重写

     View的呈现

    IView

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

    public interface IView
    {
        void Render(ViewContext viewContext, TextWriter writer);
    }
    

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

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

    RazorView 实现

    BuildManagerCompiledView 

    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 

    /// <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);
        }
    }

    以IoC的方式激活View

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

    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;
        }
    }
    

    扩展

    扩展WebViewPage

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

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

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

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

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

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

    <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>
    

    扩展RazorViewEngine

    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());
    

      

  • 相关阅读:
    Java正则表达式入门1
    JAVA中正则表达式总结
    Java正则表达式入门
    java String.valueOf()的作用
    【HDOJ】3601 Coach Yehr’s punishment
    【HDOJ】4601 Letter Tree
    【HDOJ】3686 Traffic Real Time Query System
    【HDOJ】5296 Annoying problem
    【HDOJ】3553 Just a String
    【HDOJ】4426 Palindromic Substring
  • 原文地址:https://www.cnblogs.com/wj033/p/6060699.html
Copyright © 2020-2023  润新知