1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
5 * This software is subject to the Microsoft Public License (Ms-PL).
\r
6 * A copy of the license can be found in the license.htm file included
\r
7 * in this distribution.
\r
9 * You must not remove this notice, or any other, from this software.
\r
11 * ***************************************************************************/
\r
13 namespace System.Web.Mvc {
\r
15 using System.Diagnostics.CodeAnalysis;
\r
16 using System.Globalization;
\r
19 using System.Web.Hosting;
\r
20 using System.Web.Mvc.Resources;
\r
22 public abstract class VirtualPathProviderViewEngine : IViewEngine {
\r
23 // format is ":ViewCacheEntry:{cacheType}:{prefix}:{name}:{controllerName}:"
\r
24 private const string _cacheKeyFormat = ":ViewCacheEntry:{0}:{1}:{2}:{3}:";
\r
25 private const string _cacheKeyPrefix_Master = "Master";
\r
26 private const string _cacheKeyPrefix_Partial = "Partial";
\r
27 private const string _cacheKeyPrefix_View = "View";
\r
28 private static readonly string[] _emptyLocations = new string[0];
\r
30 private VirtualPathProvider _vpp;
\r
32 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
\r
33 public string[] MasterLocationFormats {
\r
38 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
\r
39 public string[] PartialViewLocationFormats {
\r
44 public IViewLocationCache ViewLocationCache {
\r
49 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
\r
50 public string[] ViewLocationFormats {
\r
55 protected VirtualPathProvider VirtualPathProvider {
\r
58 _vpp = HostingEnvironment.VirtualPathProvider;
\r
67 protected VirtualPathProviderViewEngine() {
\r
68 if (HttpContext.Current == null || HttpContext.Current.IsDebuggingEnabled) {
\r
69 ViewLocationCache = DefaultViewLocationCache.Null;
\r
72 ViewLocationCache = new DefaultViewLocationCache();
\r
76 private string CreateCacheKey(string prefix, string name, string controllerName) {
\r
77 return String.Format(CultureInfo.InvariantCulture, _cacheKeyFormat,
\r
78 GetType().AssemblyQualifiedName, prefix, name, controllerName);
\r
81 protected abstract IView CreatePartialView(ControllerContext controllerContext, string partialPath);
\r
83 protected abstract IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath);
\r
85 protected virtual bool FileExists(ControllerContext controllerContext, string virtualPath) {
\r
86 return VirtualPathProvider.FileExists(virtualPath);
\r
89 public virtual ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) {
\r
90 if (controllerContext == null) {
\r
91 throw new ArgumentNullException("controllerContext");
\r
93 if (String.IsNullOrEmpty(partialViewName)) {
\r
94 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName");
\r
98 string controllerName = controllerContext.RouteData.GetRequiredString("controller");
\r
99 string partialPath = GetPath(controllerContext, PartialViewLocationFormats, "PartialViewLocationFormats", partialViewName, controllerName, _cacheKeyPrefix_Partial, useCache, out searched);
\r
101 if (String.IsNullOrEmpty(partialPath)) {
\r
102 return new ViewEngineResult(searched);
\r
105 return new ViewEngineResult(CreatePartialView(controllerContext, partialPath), this);
\r
108 public virtual ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) {
\r
109 if (controllerContext == null) {
\r
110 throw new ArgumentNullException("controllerContext");
\r
112 if (String.IsNullOrEmpty(viewName)) {
\r
113 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "viewName");
\r
116 string[] viewLocationsSearched;
\r
117 string[] masterLocationsSearched;
\r
119 string controllerName = controllerContext.RouteData.GetRequiredString("controller");
\r
120 string viewPath = GetPath(controllerContext, ViewLocationFormats, "ViewLocationFormats", viewName, controllerName, _cacheKeyPrefix_View, useCache, out viewLocationsSearched);
\r
121 string masterPath = GetPath(controllerContext, MasterLocationFormats, "MasterLocationFormats", masterName, controllerName, _cacheKeyPrefix_Master, useCache, out masterLocationsSearched);
\r
123 if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName))) {
\r
124 return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
\r
127 return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
\r
130 private string GetPath(ControllerContext controllerContext, string[] locations, string locationsPropertyName, string name, string controllerName, string cacheKeyPrefix, bool useCache, out string[] searchedLocations) {
\r
131 searchedLocations = _emptyLocations;
\r
133 if (String.IsNullOrEmpty(name)) {
\r
134 return String.Empty;
\r
137 if (locations == null || locations.Length == 0) {
\r
138 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
\r
139 MvcResources.Common_PropertyCannotBeNullOrEmpty, locationsPropertyName));
\r
142 bool nameRepresentsPath = IsSpecificPath(name);
\r
143 string cacheKey = CreateCacheKey(cacheKeyPrefix, name, (nameRepresentsPath) ? String.Empty : controllerName);
\r
146 string result = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, cacheKey);
\r
147 if (result != null) {
\r
152 return (nameRepresentsPath) ?
\r
153 GetPathFromSpecificName(controllerContext, name, cacheKey, ref searchedLocations) :
\r
154 GetPathFromGeneralName(controllerContext, locations, name, controllerName, cacheKey, ref searchedLocations);
\r
157 private string GetPathFromGeneralName(ControllerContext controllerContext, string[] locations, string name, string controllerName, string cacheKey, ref string[] searchedLocations) {
\r
158 string result = String.Empty;
\r
159 searchedLocations = new string[locations.Length];
\r
161 for (int i = 0; i < locations.Length; i++) {
\r
162 string virtualPath = String.Format(CultureInfo.InvariantCulture, locations[i], name, controllerName);
\r
164 if (FileExists(controllerContext, virtualPath)) {
\r
165 searchedLocations = _emptyLocations;
\r
166 result = virtualPath;
\r
167 ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result);
\r
171 searchedLocations[i] = virtualPath;
\r
177 private string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey, ref string[] searchedLocations) {
\r
178 string result = name;
\r
180 if (!FileExists(controllerContext, name)) {
\r
181 result = String.Empty;
\r
182 searchedLocations = new[] { name };
\r
185 ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result);
\r
189 private static bool IsSpecificPath(string name) {
\r
191 return (c == '~' || c == '/');
\r
194 public virtual void ReleaseView(ControllerContext controllerContext, IView view) {
\r
195 IDisposable disposable = view as IDisposable;
\r
196 if (disposable != null) {
\r
197 disposable.Dispose();
\r