WIP fixing issue with macro forms
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
|
||||
namespace Umbraco.Cms.Web.Common.Controllers
|
||||
{
|
||||
@@ -10,11 +10,20 @@ namespace Umbraco.Cms.Web.Common.Controllers
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProxyViewDataFeature"/> class.
|
||||
/// </summary>
|
||||
public ProxyViewDataFeature(ViewDataDictionary viewData) => ViewData = viewData;
|
||||
public ProxyViewDataFeature(ViewDataDictionary viewData, ITempDataDictionary tempData)
|
||||
{
|
||||
ViewData = viewData;
|
||||
TempData = tempData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ViewDataDictionary"/>
|
||||
/// </summary>
|
||||
public ViewDataDictionary ViewData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ITempDataDictionary"/>
|
||||
/// </summary>
|
||||
public ITempDataDictionary TempData { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,6 +255,7 @@ namespace Umbraco.Extensions
|
||||
builder.Services.AddUnique<IProfilerHtml, WebProfilerHtml>();
|
||||
|
||||
builder.Services.AddUnique<IMacroRenderer, MacroRenderer>();
|
||||
builder.Services.AddUnique<PartialViewMacroEngine>();
|
||||
builder.Services.AddUnique<IMemberUserKeyProvider, MemberUserKeyProvider>();
|
||||
|
||||
// register the umbraco context factory
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly IRequestAccessor _requestAccessor;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly PartialViewMacroEngine _partialViewMacroEngine;
|
||||
|
||||
public MacroRenderer(
|
||||
IProfilingLogger profilingLogger,
|
||||
@@ -52,7 +53,8 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
IMemberUserKeyProvider memberUserKeyProvider,
|
||||
ISessionManager sessionManager,
|
||||
IRequestAccessor requestAccessor,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
PartialViewMacroEngine partialViewMacroEngine)
|
||||
{
|
||||
_profilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger));
|
||||
_logger = logger;
|
||||
@@ -68,6 +70,7 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
_sessionManager = sessionManager;
|
||||
_requestAccessor = requestAccessor;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_partialViewMacroEngine = partialViewMacroEngine;
|
||||
}
|
||||
|
||||
#region MacroContent cache
|
||||
@@ -338,38 +341,28 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
private Attempt<MacroContent> ExecuteMacroOfType(MacroModel model, IPublishedContent content)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
}
|
||||
|
||||
// ensure that we are running against a published node (ie available in XML)
|
||||
// that may not be the case if the macro is embedded in a RTE of an unpublished document
|
||||
|
||||
if (content == null)
|
||||
{
|
||||
return Attempt.Fail(new MacroContent { Text = "[macro failed (no content)]" });
|
||||
}
|
||||
|
||||
var textService = _textService;
|
||||
ILocalizedTextService textService = _textService;
|
||||
|
||||
return ExecuteMacroWithErrorWrapper(model,
|
||||
$"Executing PartialView: MacroSource=\"{model.MacroSource}\".",
|
||||
"Executed PartialView.",
|
||||
() => ExecutePartialView(model, content),
|
||||
() => _partialViewMacroEngine.Execute(model, content),
|
||||
() => textService.Localize("errors/macroErrorLoadingPartialView", new[] { model.MacroSource }));
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Execute engines
|
||||
|
||||
/// <summary>
|
||||
/// Renders a PartialView Macro.
|
||||
/// </summary>
|
||||
/// <returns>The text output of the macro execution.</returns>
|
||||
private MacroContent ExecutePartialView(MacroModel macro, IPublishedContent content)
|
||||
{
|
||||
var engine = new PartialViewMacroEngine(_httpContextAccessor, _hostingEnvironment);
|
||||
return engine.Execute(macro, content);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Execution helpers
|
||||
|
||||
@@ -16,6 +16,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Core.Macros;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Web.Common.Controllers;
|
||||
using Umbraco.Extensions;
|
||||
using static Umbraco.Cms.Core.Constants.Web.Routing;
|
||||
|
||||
@@ -27,47 +28,19 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
public class PartialViewMacroEngine
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
//private readonly Func<IUmbracoContext> _getUmbracoContext;
|
||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||
private readonly ITempDataProvider _tempDataProvider;
|
||||
|
||||
public PartialViewMacroEngine(
|
||||
//IUmbracoContextAccessor umbracoContextAccessor,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IHostingEnvironment hostingEnvironment)
|
||||
IModelMetadataProvider modelMetadataProvider,
|
||||
ITempDataProvider tempDataProvider)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
|
||||
//_getUmbracoContext = () =>
|
||||
//{
|
||||
// var context = umbracoContextAccessor.UmbracoContext;
|
||||
// if (context == null)
|
||||
// {
|
||||
// throw new InvalidOperationException(
|
||||
// $"The {GetType()} cannot execute with a null UmbracoContext.Current reference.");
|
||||
// }
|
||||
|
||||
// return context;
|
||||
//};
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
_tempDataProvider = tempDataProvider;
|
||||
}
|
||||
|
||||
//public bool Validate(string code, string tempFileName, IPublishedContent currentPage, out string errorMessage)
|
||||
//{
|
||||
// var temp = GetVirtualPathFromPhysicalPath(tempFileName);
|
||||
// try
|
||||
// {
|
||||
// CompileAndInstantiate(temp);
|
||||
// }
|
||||
// catch (Exception exception)
|
||||
// {
|
||||
// errorMessage = exception.Message;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// errorMessage = string.Empty;
|
||||
// return true;
|
||||
//}
|
||||
|
||||
public MacroContent Execute(MacroModel macro, IPublishedContent content)
|
||||
{
|
||||
if (macro == null)
|
||||
@@ -85,31 +58,32 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
throw new ArgumentException("The MacroSource property of the macro object cannot be null or empty");
|
||||
}
|
||||
|
||||
var httpContext = _httpContextAccessor.GetRequiredHttpContext();
|
||||
//var umbCtx = _getUmbracoContext();
|
||||
var routeVals = new RouteData();
|
||||
routeVals.Values.Add(ControllerToken, "PartialViewMacro");
|
||||
routeVals.Values.Add(ActionToken, "Index");
|
||||
HttpContext httpContext = _httpContextAccessor.GetRequiredHttpContext();
|
||||
//var routeVals = new RouteData();
|
||||
//routeVals.Values.Add(ControllerToken, "PartialViewMacro");
|
||||
//routeVals.Values.Add(ActionToken, "Index");
|
||||
|
||||
//TODO: Was required for UmbracoViewPage need to figure out if we still need that, i really don't think this is necessary
|
||||
//routeVals.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbCtx);
|
||||
|
||||
var modelMetadataProvider = httpContext.RequestServices.GetRequiredService<IModelMetadataProvider>();
|
||||
var tempDataProvider = httpContext.RequestServices.GetRequiredService<ITempDataProvider>();
|
||||
RouteData currentRouteData = httpContext.GetRouteData();
|
||||
|
||||
// Check if there's proxied ViewData (i.e. returned from a SurfaceController)
|
||||
ProxyViewDataFeature proxyViewDataFeature = httpContext.Features.Get<ProxyViewDataFeature>();
|
||||
ViewDataDictionary viewData = proxyViewDataFeature?.ViewData ?? new ViewDataDictionary(_modelMetadataProvider, new ModelStateDictionary());
|
||||
ITempDataDictionary tempData = proxyViewDataFeature?.TempData ?? new TempDataDictionary(httpContext, _tempDataProvider);
|
||||
|
||||
var viewContext = new ViewContext(
|
||||
new ActionContext(httpContext, httpContext.GetRouteData(), new ControllerActionDescriptor()),
|
||||
new ActionContext(httpContext, currentRouteData, new ControllerActionDescriptor()),
|
||||
new FakeView(),
|
||||
new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary()),
|
||||
new TempDataDictionary(httpContext, tempDataProvider),
|
||||
viewData,
|
||||
tempData,
|
||||
TextWriter.Null,
|
||||
new HtmlHelperOptions()
|
||||
);
|
||||
|
||||
|
||||
routeVals.DataTokens.Add("ParentActionViewContext", viewContext);
|
||||
|
||||
var viewComponent = new PartialViewMacroViewComponent(macro, content);
|
||||
//routeVals.DataTokens.Add("ParentActionViewContext", viewContext);
|
||||
|
||||
var writer = new StringWriter();
|
||||
var viewComponentContext = new ViewComponentContext(
|
||||
@@ -119,7 +93,9 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
viewContext,
|
||||
writer);
|
||||
|
||||
viewComponent.InvokeAsync().GetAwaiter().GetResult().Execute(viewComponentContext);
|
||||
var viewComponent = new PartialViewMacroViewComponent(macro, content, viewComponentContext);
|
||||
|
||||
viewComponent.Invoke().Execute(viewComponentContext);
|
||||
|
||||
var output = writer.GetStringBuilder().ToString();
|
||||
|
||||
@@ -129,38 +105,11 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
private class FakeView : IView
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task RenderAsync(ViewContext context)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public Task RenderAsync(ViewContext context) => Task.CompletedTask;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Path { get; } = "View";
|
||||
}
|
||||
|
||||
//private string GetVirtualPathFromPhysicalPath(string physicalPath)
|
||||
//{
|
||||
// var rootpath = _hostingEnvironment.MapPathContentRoot("~/");
|
||||
// physicalPath = physicalPath.Replace(rootpath, "");
|
||||
// physicalPath = physicalPath.Replace("\\", "/");
|
||||
// return "~/" + physicalPath;
|
||||
//}
|
||||
|
||||
//private static PartialViewMacroPage CompileAndInstantiate(string virtualPath)
|
||||
//{
|
||||
// // //Compile Razor - We Will Leave This To ASP.NET Compilation Engine & ASP.NET WebPages
|
||||
// // //Security in medium trust is strict around here, so we can only pass a virtual file path
|
||||
// // //ASP.NET Compilation Engine caches returned types
|
||||
// // //Changed From BuildManager As Other Properties Are Attached Like Context Path/
|
||||
// // var webPageBase = WebPageBase.CreateInstanceFromVirtualPath(virtualPath);
|
||||
// // var webPage = webPageBase as PartialViewMacroPage;
|
||||
// // if (webPage == null)
|
||||
// // throw new InvalidCastException("All Partial View Macro views must inherit from " + typeof(PartialViewMacroPage).FullName);
|
||||
// // return webPage;
|
||||
|
||||
// //TODO? How to check this
|
||||
// return null;
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ViewComponents;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.Macros;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
@@ -20,13 +21,17 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
|
||||
public PartialViewMacroViewComponent(
|
||||
MacroModel macro,
|
||||
IPublishedContent content)
|
||||
IPublishedContent content,
|
||||
ViewComponentContext viewComponentContext)
|
||||
{
|
||||
_macro = macro;
|
||||
_content = content;
|
||||
// This must be set before Invoke is called else the call to View will end up
|
||||
// using an empty ViewData instance because this hasn't been set yet.
|
||||
ViewComponentContext = viewComponentContext;
|
||||
}
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync()
|
||||
public IViewComponentResult Invoke()
|
||||
{
|
||||
var model = new PartialViewMacroModel(
|
||||
_content,
|
||||
@@ -34,7 +39,8 @@ namespace Umbraco.Cms.Web.Common.Macros
|
||||
_macro.Alias,
|
||||
_macro.Name,
|
||||
_macro.Properties.ToDictionary(x => x.Key, x => (object)x.Value));
|
||||
var result = View(_macro.MacroSource, model);
|
||||
|
||||
ViewViewComponentResult result = View(_macro.MacroSource, model);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -36,9 +36,10 @@ namespace Umbraco.Cms.Web.Common.Templates
|
||||
private readonly IFileService _fileService;
|
||||
private readonly ILocalizationService _languageService;
|
||||
private readonly WebRoutingSettings _webRoutingSettings;
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ICompositeViewEngine _viewEngine;
|
||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||
private readonly ITempDataProvider _tempDataProvider;
|
||||
|
||||
public TemplateRenderer(
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
@@ -46,18 +47,20 @@ namespace Umbraco.Cms.Web.Common.Templates
|
||||
IFileService fileService,
|
||||
ILocalizationService textService,
|
||||
IOptions<WebRoutingSettings> webRoutingSettings,
|
||||
IShortStringHelper shortStringHelper,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
ICompositeViewEngine viewEngine)
|
||||
ICompositeViewEngine viewEngine,
|
||||
IModelMetadataProvider modelMetadataProvider,
|
||||
ITempDataProvider tempDataProvider)
|
||||
{
|
||||
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
|
||||
_publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter));
|
||||
_fileService = fileService ?? throw new ArgumentNullException(nameof(fileService));
|
||||
_languageService = textService ?? throw new ArgumentNullException(nameof(textService));
|
||||
_webRoutingSettings = webRoutingSettings.Value ?? throw new ArgumentNullException(nameof(webRoutingSettings));
|
||||
_shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper));
|
||||
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
|
||||
_viewEngine = viewEngine ?? throw new ArgumentNullException(nameof(viewEngine));
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
_tempDataProvider = tempDataProvider;
|
||||
}
|
||||
|
||||
public async Task RenderAsync(int pageId, int? altTemplateId, StringWriter writer)
|
||||
@@ -156,10 +159,7 @@ namespace Umbraco.Cms.Web.Common.Templates
|
||||
throw new InvalidOperationException($"A view with the name {request.GetTemplateAlias()} could not be found");
|
||||
}
|
||||
|
||||
var modelMetadataProvider = httpContext.RequestServices.GetRequiredService<IModelMetadataProvider>();
|
||||
var tempDataProvider = httpContext.RequestServices.GetRequiredService<ITempDataProvider>();
|
||||
|
||||
var viewData = new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary())
|
||||
var viewData = new ViewDataDictionary(_modelMetadataProvider, new ModelStateDictionary())
|
||||
{
|
||||
Model = request.PublishedContent
|
||||
};
|
||||
@@ -169,7 +169,7 @@ namespace Umbraco.Cms.Web.Common.Templates
|
||||
new ActionContext(httpContext, httpContext.GetRouteData(), new ControllerActionDescriptor()),
|
||||
viewResult.View,
|
||||
viewData,
|
||||
new TempDataDictionary(httpContext, tempDataProvider),
|
||||
new TempDataDictionary(httpContext, _tempDataProvider),
|
||||
writer,
|
||||
new HtmlHelperOptions()
|
||||
);
|
||||
@@ -182,6 +182,9 @@ namespace Umbraco.Cms.Web.Common.Templates
|
||||
sw.Write(output);
|
||||
}
|
||||
|
||||
// TODO: I feel like we need to do more than this, pretty sure we need to replace the UmbracoRouteValues
|
||||
// HttpRequest feature too while this renders.
|
||||
|
||||
private void SetNewItemsOnContextObjects(IPublishedRequest request)
|
||||
{
|
||||
// now, set the new ones for this page execution
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Umbraco.Cms.Web.Website.Controllers
|
||||
/// </summary>
|
||||
protected UmbracoPageResult CurrentUmbracoPage()
|
||||
{
|
||||
HttpContext.Features.Set(new ProxyViewDataFeature(ViewData));
|
||||
HttpContext.Features.Set(new ProxyViewDataFeature(ViewData, TempData));
|
||||
return new UmbracoPageResult(ProfilingLogger);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Logging;
|
||||
@@ -35,6 +36,9 @@ namespace Umbraco.Cms.Web.Website.Controllers
|
||||
return CurrentUmbracoPage();
|
||||
}
|
||||
|
||||
// TODO: This is supposed to be for members! not users
|
||||
//throw new NotImplementedException("Implement this for members");
|
||||
|
||||
if (await _websiteSecurityAccessor.WebsiteSecurity.LoginAsync(model.Username, model.Password) == false)
|
||||
{
|
||||
// Don't add a field level error, just model level.
|
||||
|
||||
@@ -165,16 +165,11 @@ namespace Umbraco.Extensions
|
||||
return htmlHelper.ValidationSummary(excludePropertyErrors, message, htmlAttributes);
|
||||
}
|
||||
|
||||
var htmlGenerator = GetRequiredService<IHtmlGenerator>(htmlHelper);
|
||||
IHtmlGenerator htmlGenerator = GetRequiredService<IHtmlGenerator>(htmlHelper);
|
||||
|
||||
var viewContext = htmlHelper.ViewContext.Clone();
|
||||
foreach (var key in viewContext.ViewData.Keys.ToArray())
|
||||
{
|
||||
if (!key.StartsWith(prefix))
|
||||
{
|
||||
viewContext.ViewData.Remove(key);
|
||||
}
|
||||
}
|
||||
ViewContext viewContext = htmlHelper.ViewContext.Clone();
|
||||
//change the HTML field name
|
||||
viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = prefix;
|
||||
|
||||
var tagBuilder = htmlGenerator.GenerateValidationSummary(
|
||||
viewContext,
|
||||
|
||||
Reference in New Issue
Block a user