Merge pull request #9336 from umbraco/netcore/feature/migrate_custom_view_engines

Netcore: Migrate our custom view engines
This commit is contained in:
Mole
2020-11-04 10:08:51 +01:00
committed by GitHub
18 changed files with 391 additions and 329 deletions

View File

@@ -20,7 +20,7 @@
public const string AppCode = "~/App_Code";
public const string AppPlugins = "~/App_Plugins";
public const string AppPlugins = "/App_Plugins";
public const string MvcViews = "~/Views";

View File

@@ -0,0 +1,75 @@
using Microsoft.AspNetCore.Mvc;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Logging;
using Umbraco.Web.Website.ViewEngines;
namespace Umbraco.Tests.Runtimes
{
[TestFixture]
public class ProfilingViewEngineWrapperMvcViewOptionsSetupTests
{
private ProfilingViewEngineWrapperMvcViewOptionsSetup Sut =>
new ProfilingViewEngineWrapperMvcViewOptionsSetup(Mock.Of<IProfiler>());
[Test]
public void WrapViewEngines_HasEngines_WrapsAll()
{
var options = new MvcViewOptions()
{
ViewEngines =
{
Mock.Of<IRenderViewEngine>(),
Mock.Of<IPluginViewEngine>(),
}
};
Sut.Configure(options);
Assert.That(options.ViewEngines.Count, Is.EqualTo(2));
Assert.That(options.ViewEngines[0], Is.InstanceOf<ProfilingViewEngine>());
Assert.That(options.ViewEngines[1], Is.InstanceOf<ProfilingViewEngine>());
}
[Test]
public void WrapViewEngines_HasEngines_KeepsSortOrder()
{
var options = new MvcViewOptions()
{
ViewEngines =
{
Mock.Of<IRenderViewEngine>(),
Mock.Of<IPluginViewEngine>(),
}
};
Sut.Configure(options);
Assert.That(options.ViewEngines.Count, Is.EqualTo(2));
Assert.That(((ProfilingViewEngine)options.ViewEngines[0]).Inner, Is.InstanceOf<IRenderViewEngine>());
Assert.That(((ProfilingViewEngine)options.ViewEngines[1]).Inner, Is.InstanceOf<IPluginViewEngine>());
}
[Test]
public void WrapViewEngines_HasProfiledEngine_AddsSameInstance()
{
var profiledEngine = new ProfilingViewEngine(Mock.Of<IPluginViewEngine>(), Mock.Of<IProfiler>());
var options = new MvcViewOptions()
{
ViewEngines =
{
profiledEngine
}
};
Sut.Configure(options);
Assert.That(options.ViewEngines[0], Is.SameAs(profiledEngine));
}
[Test]
public void WrapViewEngines_CollectionIsNull_DoesNotThrow()
{
Assert.DoesNotThrow(() => Sut.Configure(new MvcViewOptions()));
}
}
}

View File

@@ -1,66 +0,0 @@
using System.Collections.Generic;
using System.Web.Mvc;
using NUnit.Framework;
using NUnit.Framework.Internal;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Mvc;
using Umbraco.Web.Runtime;
namespace Umbraco.Tests.Runtimes
{
[TestFixture]
public class WebRuntimeComponentTests
{
[Test]
public void WrapViewEngines_HasEngines_WrapsAll()
{
IList<IViewEngine> engines = new List<IViewEngine>
{
new RenderViewEngine(TestHelper.GetHostingEnvironment()),
new PluginViewEngine()
};
WebInitialComponent.WrapViewEngines(engines);
Assert.That(engines.Count, Is.EqualTo(2));
Assert.That(engines[0], Is.InstanceOf<ProfilingViewEngine>());
Assert.That(engines[1], Is.InstanceOf<ProfilingViewEngine>());
}
[Test]
public void WrapViewEngines_HasEngines_KeepsSortOrder()
{
IList<IViewEngine> engines = new List<IViewEngine>
{
new RenderViewEngine(TestHelper.GetHostingEnvironment()),
new PluginViewEngine()
};
WebInitialComponent.WrapViewEngines(engines);
Assert.That(engines.Count, Is.EqualTo(2));
Assert.That(((ProfilingViewEngine)engines[0]).Inner, Is.InstanceOf<RenderViewEngine>());
Assert.That(((ProfilingViewEngine)engines[1]).Inner, Is.InstanceOf<PluginViewEngine>());
}
[Test]
public void WrapViewEngines_HasProfiledEngine_AddsSameInstance()
{
var profiledEngine = new ProfilingViewEngine(new PluginViewEngine());
IList<IViewEngine> engines = new List<IViewEngine>
{
profiledEngine
};
WebInitialComponent.WrapViewEngines(engines);
Assert.That(engines[0], Is.SameAs(profiledEngine));
}
[Test]
public void WrapViewEngines_CollectionIsNull_DoesNotThrow()
{
Assert.DoesNotThrow(() => WebInitialComponent.WrapViewEngines(null));
}
}
}

View File

@@ -216,7 +216,6 @@
<Compile Include="Testing\TestingTests\MockTests.cs" />
<Compile Include="Web\Mvc\SurfaceControllerTests.cs" />
<Compile Include="Runtimes\CoreRuntimeTests.cs" />
<Compile Include="Runtimes\WebRuntimeComponentTests.cs" />
<Compile Include="Web\Mvc\MergeParentContextViewDataAttributeTests.cs" />
<Compile Include="Web\Mvc\ViewDataDictionaryExtensionTests.cs" />
<Compile Include="Persistence\Querying\ContentTypeSqlMappingTests.cs" />

View File

@@ -1,5 +1,11 @@
using Microsoft.AspNetCore.Mvc.Controllers;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Web.Website.ViewEngines;
namespace Umbraco.Extensions
{
@@ -8,6 +14,18 @@ namespace Umbraco.Extensions
public static void AddUmbracoWebsite(this IServiceCollection services)
{
services.AddSingleton<IControllerActivator, ServiceBasedControllerActivator>();
// Set the render & plugin view engines (Super complicated, but this allows us to use the IServiceCollection
// to inject dependencies into the viewEngines)
services.AddTransient<IConfigureOptions<MvcViewOptions>, RenderMvcViewOptionsSetup>();
services.AddSingleton<IRenderViewEngine, RenderViewEngine>();
services.AddTransient<IConfigureOptions<MvcViewOptions>, PluginMvcViewOptionsSetup>();
services.AddSingleton<IPluginViewEngine, PluginViewEngine>();
// Wraps all existing view engines in a ProfilerViewEngine
services.AddTransient<IConfigureOptions<MvcViewOptions>, ProfilingViewEngineWrapperMvcViewOptionsSetup>();
}
}
}

View File

@@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Mvc.Razor;
namespace Umbraco.Web.Website.ViewEngines
{
public interface IPluginViewEngine : IRazorViewEngine
{
}
}

View File

@@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Mvc.Razor;
namespace Umbraco.Web.Website.ViewEngines
{
public interface IRenderViewEngine : IRazorViewEngine
{
}
}

View File

@@ -0,0 +1,26 @@
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Umbraco.Web.Website.ViewEngines
{
public class PluginMvcViewOptionsSetup : IConfigureOptions<MvcViewOptions>
{
private readonly IPluginViewEngine _pluginViewEngine;
public PluginMvcViewOptionsSetup(IPluginViewEngine pluginViewEngine)
{
_pluginViewEngine = pluginViewEngine ?? throw new ArgumentNullException(nameof(pluginViewEngine));
}
public void Configure(MvcViewOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
options.ViewEngines.Add(_pluginViewEngine);
}
}
}

View File

@@ -0,0 +1,48 @@
using System.Diagnostics;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Umbraco.Web.Website.ViewEngines
{
/// <summary>
/// A view engine to look into the App_Plugins folder for views for packaged controllers
/// </summary>
public class PluginViewEngine : RazorViewEngine, IPluginViewEngine
{
public PluginViewEngine(
IRazorPageFactoryProvider pageFactory,
IRazorPageActivator pageActivator,
HtmlEncoder htmlEncoder,
ILoggerFactory loggerFactory,
DiagnosticListener diagnosticListener)
: base(pageFactory, pageActivator, htmlEncoder, OverrideViewLocations(), loggerFactory, diagnosticListener)
{
}
private static IOptions<RazorViewEngineOptions> OverrideViewLocations()
{
return Options.Create(new RazorViewEngineOptions()
{
AreaViewLocationFormats =
{
//set all of the area view locations to the plugin folder
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/{1}/{0}.cshtml"),
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/Shared/{0}.cshtml"),
//will be used when we have partial view and child action macros
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/Partials/{0}.cshtml"),
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/MacroPartials/{0}.cshtml"),
//for partialsCurrent.
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/{1}/{0}.cshtml"),
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/Shared/{0}.cshtml"),
},
ViewLocationFormats =
{
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/{1}/{0}.cshtml"),
}
});
}
}
}

View File

@@ -0,0 +1,45 @@

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Umbraco.Core.Logging;
namespace Umbraco.Web.Website.ViewEngines
{
public class ProfilingViewEngine: IViewEngine
{
internal readonly IViewEngine Inner;
private readonly IProfiler _profiler;
private readonly string _name;
public ProfilingViewEngine(IViewEngine inner, IProfiler profiler)
{
Inner = inner;
_profiler = profiler;
_name = inner.GetType().Name;
}
public ViewEngineResult FindView(ActionContext context, string viewName, bool isMainPage)
{
using (_profiler.Step(string.Format("{0}.FindView, {1}, {2}", _name, viewName, isMainPage)))
{
return WrapResult(Inner.FindView(context, viewName, isMainPage));
}
}
private static ViewEngineResult WrapResult(ViewEngineResult innerResult)
{
var profiledResult = innerResult.View is null
? ViewEngineResult.NotFound(innerResult.ViewName, innerResult.SearchedLocations)
: ViewEngineResult.Found(innerResult.ViewName, innerResult.View);
return profiledResult;
}
public ViewEngineResult GetView(string executingFilePath, string viewPath, bool isMainPage)
{
using (_profiler.Step(string.Format("{0}.GetView, {1}, {2}, {3}", _name, executingFilePath, viewPath, isMainPage)))
{
return Inner.GetView(executingFilePath, viewPath, isMainPage);
}
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.Extensions.Options;
using Umbraco.Core.Logging;
namespace Umbraco.Web.Website.ViewEngines
{
public class ProfilingViewEngineWrapperMvcViewOptionsSetup : IConfigureOptions<MvcViewOptions>
{
private readonly IProfiler _profiler;
public ProfilingViewEngineWrapperMvcViewOptionsSetup(IProfiler profiler)
{
_profiler = profiler ?? throw new ArgumentNullException(nameof(profiler));
}
public void Configure(MvcViewOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
WrapViewEngines(options.ViewEngines);
}
private void WrapViewEngines(IList<IViewEngine> viewEngines)
{
if (viewEngines == null || viewEngines.Count == 0) return;
var originalEngines = viewEngines.ToList();
viewEngines.Clear();
foreach (var engine in originalEngines)
{
var wrappedEngine = engine is ProfilingViewEngine ? engine : new ProfilingViewEngine(engine, _profiler);
viewEngines.Add(wrappedEngine);
}
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Umbraco.Web.Website.ViewEngines
{
public class RenderMvcViewOptionsSetup : IConfigureOptions<MvcViewOptions>
{
private readonly IRenderViewEngine _renderViewEngine;
public RenderMvcViewOptionsSetup(IRenderViewEngine renderViewEngine)
{
_renderViewEngine = renderViewEngine ?? throw new ArgumentNullException(nameof(renderViewEngine));
}
public void Configure(MvcViewOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
options.ViewEngines.Add(_renderViewEngine);
}
}
}

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Core.Hosting;
using Umbraco.Extensions;
using Umbraco.Web.Models;
namespace Umbraco.Web.Website.ViewEngines
{
/// <summary>
/// A view engine to look into the template location specified in the config for the front-end/Rendering part of the cms,
/// this includes paths to render partial macros and media item templates.
/// </summary>
public class RenderViewEngine : RazorViewEngine, IRenderViewEngine
{
public RenderViewEngine(
IRazorPageFactoryProvider pageFactory,
IRazorPageActivator pageActivator,
HtmlEncoder htmlEncoder,
ILoggerFactory loggerFactory,
DiagnosticListener diagnosticListener)
: base(pageFactory, pageActivator, htmlEncoder, OverrideViewLocations(), loggerFactory, diagnosticListener)
{
}
private static IOptions<RazorViewEngineOptions> OverrideViewLocations()
{
return Options.Create<RazorViewEngineOptions>(new RazorViewEngineOptions()
{
//NOTE: we will make the main view location the last to be searched since if it is the first to be searched and there is both a view and a partial
// view in both locations and the main view is rendering a partial view with the same name, we will get a stack overflow exception.
// http://issues.umbraco.org/issue/U4-1287, http://issues.umbraco.org/issue/U4-1215
ViewLocationFormats =
{
"/Partials/{0}.cshtml",
"/MacroPartials/{0}.cshtml",
"/{0}.cshtml"
},
AreaViewLocationFormats =
{
"/Partials/{0}.cshtml",
"/MacroPartials/{0}.cshtml",
"/{0}.cshtml"
}
});
}
public new ViewEngineResult FindView(ActionContext context, string viewName, bool isMainPage)
{
return ShouldFindView(context, isMainPage)
? base.FindView(context, viewName, isMainPage)
: ViewEngineResult.NotFound(viewName, Array.Empty<string>());
}
/// <summary>
/// Determines if the view should be found, this is used for view lookup performance and also to ensure
/// less overlap with other user's view engines. This will return true if the Umbraco back office is rendering
/// and its a partial view or if the umbraco front-end is rendering but nothing else.
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="isPartial"></param>
/// <returns></returns>
private static bool ShouldFindView(ActionContext context, bool isMainPage)
{
//In v8, this was testing recursively into if it was a child action, but child action do not exist anymore,
//And my best guess is that it
context.RouteData.DataTokens.TryGetValue(Core.Constants.Web.UmbracoDataToken, out var umbracoToken);
// first check if we're rendering a partial view for the back office, or surface controller, etc...
// anything that is not ContentModel as this should only pertain to Umbraco views.
if (!isMainPage && !(umbracoToken is ContentModel))
return true;
// only find views if we're rendering the umbraco front end
return umbracoToken is ContentModel;
}
}
}

View File

@@ -1,99 +0,0 @@
using System.IO;
using System.Linq;
using System.Web.Mvc;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Mvc
{
/// <summary>
/// A view engine to look into the App_Plugins folder for views for packaged controllers
/// </summary>
public class PluginViewEngine : RazorViewEngine
{
/// <summary>
/// Constructor
/// </summary>
public PluginViewEngine()
{
SetViewLocations();
}
private void SetViewLocations()
{
//these are the originals:
//base.AreaViewLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/{1}/{0}.vbhtml", "~/Areas/{2}/Views/Shared/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.vbhtml" };
//base.AreaMasterLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/{1}/{0}.vbhtml", "~/Areas/{2}/Views/Shared/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.vbhtml" };
//base.AreaPartialViewLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/{1}/{0}.vbhtml", "~/Areas/{2}/Views/Shared/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.vbhtml" };
//base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml", "~/Views/Shared/{0}.vbhtml" };
//base.MasterLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml", "~/Views/Shared/{0}.vbhtml" };
//base.PartialViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml", "~/Views/Shared/{0}.vbhtml" };
//base.FileExtensions = new string[] { "cshtml", "vbhtml" };
var viewLocationsArray = new[]
{
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/{1}/{0}.cshtml"),
};
//set all of the area view locations to the plugin folder
AreaViewLocationFormats = viewLocationsArray
.Concat(new[]
{
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/Shared/{0}.cshtml"),
})
.ToArray();
AreaMasterLocationFormats = viewLocationsArray;
AreaPartialViewLocationFormats = new[]
{
//will be used when we have partial view and child action macros
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/Partials/{0}.cshtml"),
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/MacroPartials/{0}.cshtml"),
//for partialsCurrent.
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/{1}/{0}.cshtml"),
string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/Shared/{0}.cshtml"),
};
}
/// <summary>
/// Ensures that the correct web.config for razor exists in the /Views folder.
/// </summary>
private void EnsureFolderAndWebConfig(ViewEngineResult result)
{
if (result.View == null) return;
var razorResult = result.View as RazorView;
if (razorResult == null) return;
var folder = Path.GetDirectoryName(Current.IOHelper.MapPath(razorResult.ViewPath));
//now we need to get the /View/ folder
var viewFolder = folder.Substring(0, folder.LastIndexOf("\\Views\\")) + "\\Views";
//ensure the web.config file is in the ~/Views folder
Directory.CreateDirectory(viewFolder);
if (!File.Exists(Path.Combine(viewFolder, "web.config")))
{
using (var writer = File.CreateText(Path.Combine(viewFolder, "web.config")))
{
writer.Write(Strings.WebConfigTemplate);
}
}
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
var result = base.FindView(controllerContext, viewName, masterName, useCache);
EnsureFolderAndWebConfig(result);
return result;
}
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
var result = base.FindPartialView(controllerContext, partialViewName, useCache);
EnsureFolderAndWebConfig(result);
return result;
}
}
}

View File

@@ -1,49 +0,0 @@
using System.Web.Mvc;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Mvc
{
public class ProfilingViewEngine: IViewEngine
{
internal readonly IViewEngine Inner;
private readonly string _name;
public ProfilingViewEngine(IViewEngine inner)
{
Inner = inner;
_name = inner.GetType().Name;
}
public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
using (Current.Profiler.Step(string.Format("{0}.FindPartialView, {1}, {2}", _name, partialViewName, useCache)))
{
return WrapResult(Inner.FindPartialView(controllerContext, partialViewName, useCache));
}
}
public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
using (Current.Profiler.Step(string.Format("{0}.FindView, {1}, {2}, {3}", _name, viewName, masterName, useCache)))
{
return WrapResult(Inner.FindView(controllerContext, viewName, masterName, useCache));
}
}
private static ViewEngineResult WrapResult(ViewEngineResult innerResult)
{
var profiledResult = innerResult.View != null ?
new ViewEngineResult(new ProfilingView(innerResult.View), innerResult.ViewEngine) :
new ViewEngineResult(innerResult.SearchedLocations);
return profiledResult;
}
public void ReleaseView(ControllerContext controllerContext, IView view)
{
using (Current.Profiler.Step(string.Format("{0}.ReleaseView, {1}", _name, view.GetType().Name)))
{
Inner.ReleaseView(controllerContext, view);
}
}
}
}

View File

@@ -1,106 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using Umbraco.Core.Composing;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Web.Models;
namespace Umbraco.Web.Mvc
{
/// <summary>
/// A view engine to look into the template location specified in the config for the front-end/Rendering part of the cms,
/// this includes paths to render partial macros and media item templates.
/// </summary>
public class RenderViewEngine : RazorViewEngine
{
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IEnumerable<string> _supplementedViewLocations = new[] { "/{0}.cshtml" };
//NOTE: we will make the main view location the last to be searched since if it is the first to be searched and there is both a view and a partial
// view in both locations and the main view is rendering a partial view with the same name, we will get a stack overflow exception.
// http://issues.umbraco.org/issue/U4-1287, http://issues.umbraco.org/issue/U4-1215
private readonly IEnumerable<string> _supplementedPartialViewLocations = new[] { "/Partials/{0}.cshtml", "/MacroPartials/{0}.cshtml", "/{0}.cshtml" };
/// <summary>
/// Constructor
/// </summary>
public RenderViewEngine(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
const string templateFolder = Constants.ViewLocation;
// the Render view engine doesn't support Area's so make those blank
ViewLocationFormats = _supplementedViewLocations.Select(x => templateFolder + x).ToArray();
PartialViewLocationFormats = _supplementedPartialViewLocations.Select(x => templateFolder + x).ToArray();
AreaPartialViewLocationFormats = Array.Empty<string>();
AreaViewLocationFormats = Array.Empty<string>();
EnsureFoldersAndFiles();
}
/// <summary>
/// Ensures that the correct web.config for razor exists in the /Views folder, the partials folder exist and the ViewStartPage exists.
/// </summary>
private void EnsureFoldersAndFiles()
{
var viewFolder = _hostingEnvironment.MapPathContentRoot(Constants.ViewLocation);
// ensure the web.config file is in the ~/Views folder
Directory.CreateDirectory(viewFolder);
var webConfigPath = Path.Combine(viewFolder, "web.config");
if (File.Exists(webConfigPath) == false)
{
using (var writer = File.CreateText(webConfigPath))
{
writer.Write(Strings.WebConfigTemplate);
}
}
//auto create the partials folder
var partialsFolder = Path.Combine(viewFolder, "Partials");
Directory.CreateDirectory(partialsFolder);
// We could create a _ViewStart page if it isn't there as well, but we may not allow editing of this page in the back office.
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
return ShouldFindView(controllerContext, false)
? base.FindView(controllerContext, viewName, masterName, useCache)
: new ViewEngineResult(new string[] { });
}
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
return ShouldFindView(controllerContext, true)
? base.FindPartialView(controllerContext, partialViewName, useCache)
: new ViewEngineResult(new string[] { });
}
/// <summary>
/// Determines if the view should be found, this is used for view lookup performance and also to ensure
/// less overlap with other user's view engines. This will return true if the Umbraco back office is rendering
/// and its a partial view or if the umbraco front-end is rendering but nothing else.
/// </summary>
/// <param name="controllerContext"></param>
/// <param name="isPartial"></param>
/// <returns></returns>
private static bool ShouldFindView(ControllerContext controllerContext, bool isPartial)
{
var umbracoToken = controllerContext.GetDataTokenInViewContextHierarchy(Core.Constants.Web.UmbracoDataToken);
// first check if we're rendering a partial view for the back office, or surface controller, etc...
// anything that is not ContentModel as this should only pertain to Umbraco views.
if (isPartial && !(umbracoToken is ContentModel))
return true;
// only find views if we're rendering the umbraco front end
return umbracoToken is ContentModel;
}
}
}

View File

@@ -78,7 +78,7 @@ namespace Umbraco.Web.Runtime
viewEngines.Clear();
foreach (var engine in originalEngines)
{
var wrappedEngine = engine is ProfilingViewEngine ? engine : new ProfilingViewEngine(engine);
var wrappedEngine = engine;// TODO introduce in NETCORE: is ProfilingViewEngine ? engine : new ProfilingViewEngine(engine);
viewEngines.Add(wrappedEngine);
}
}
@@ -93,8 +93,8 @@ namespace Umbraco.Web.Runtime
// ControllerBuilder.Current.SetControllerFactory(controllerFactory);
// set the render & plugin view engines
ViewEngines.Engines.Add(new RenderViewEngine(_hostingEnvironment));
ViewEngines.Engines.Add(new PluginViewEngine());
// ViewEngines.Engines.Add(new RenderViewEngine(_hostingEnvironment));
// ViewEngines.Engines.Add(new PluginViewEngine());
////add the profiling action filter
//GlobalFilters.Filters.Add(new ProfilingActionFilter());

View File

@@ -228,7 +228,6 @@
<Compile Include="UmbracoDefaultOwinStartup.cs" />
<Compile Include="HtmlStringUtilities.cs" />
<Compile Include="Mvc\ProfilingView.cs" />
<Compile Include="Mvc\ProfilingViewEngine.cs" />
<Compile Include="CacheHelperExtensions.cs" />
<Compile Include="Editors\AuthenticationController.cs" />
<Compile Include="Controllers\UmbProfileController.cs" />
@@ -293,7 +292,6 @@
<Compile Include="Mvc\IHtmlTagWrapper.cs" />
<Compile Include="Mvc\MergeModelStateToChildActionAttribute.cs" />
<Compile Include="Mvc\PluginController.cs" />
<Compile Include="Mvc\PluginViewEngine.cs" />
<Compile Include="Mvc\PostedDataProxyInfo.cs" />
<Compile Include="Mvc\RedirectToUmbracoPageResult.cs" />
<Compile Include="Mvc\Strings.Designer.cs">
@@ -314,7 +312,6 @@
<Compile Include="Mvc\RenderActionInvoker.cs" />
<Compile Include="Mvc\RenderControllerFactory.cs" />
<Compile Include="Mvc\RenderRouteHandler.cs" />
<Compile Include="Mvc\RenderViewEngine.cs" />
<Compile Include="Mvc\RouteDefinition.cs" />
<Compile Include="Mvc\RouteValueDictionaryExtensions.cs" />
<Compile Include="WebApi\UmbracoAuthorizeAttribute.cs" />