Merge pull request #9336 from umbraco/netcore/feature/migrate_custom_view_engines
Netcore: Migrate our custom view engines
This commit is contained in:
@@ -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";
|
||||
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
8
src/Umbraco.Web.Website/ViewEngines/IPluginViewEngine.cs
Normal file
8
src/Umbraco.Web.Website/ViewEngines/IPluginViewEngine.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
|
||||
namespace Umbraco.Web.Website.ViewEngines
|
||||
{
|
||||
public interface IPluginViewEngine : IRazorViewEngine
|
||||
{
|
||||
}
|
||||
}
|
||||
8
src/Umbraco.Web.Website/ViewEngines/IRenderViewEngine.cs
Normal file
8
src/Umbraco.Web.Website/ViewEngines/IRenderViewEngine.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
|
||||
namespace Umbraco.Web.Website.ViewEngines
|
||||
{
|
||||
public interface IRenderViewEngine : IRazorViewEngine
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/Umbraco.Web.Website/ViewEngines/PluginViewEngine.cs
Normal file
48
src/Umbraco.Web.Website/ViewEngines/PluginViewEngine.cs
Normal 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"),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/Umbraco.Web.Website/ViewEngines/ProfilingViewEngine.cs
Normal file
45
src/Umbraco.Web.Website/ViewEngines/ProfilingViewEngine.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/Umbraco.Web.Website/ViewEngines/RenderViewEngine.cs
Normal file
89
src/Umbraco.Web.Website/ViewEngines/RenderViewEngine.cs
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user