Merge branch 'netcore/dev' into netcore/members-userstore
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -10,26 +11,33 @@ namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
public class AspNetCoreHostingEnvironment : Core.Hosting.IHostingEnvironment
|
||||
{
|
||||
private IOptionsMonitor<HostingSettings> _hostingSettings;
|
||||
private readonly ISet<Uri> _applicationUrls = new HashSet<Uri>();
|
||||
private readonly IOptionsMonitor<HostingSettings> _hostingSettings;
|
||||
private readonly IOptionsMonitor<WebRoutingSettings> _webRoutingSettings;
|
||||
private readonly IWebHostEnvironment _webHostEnvironment;
|
||||
|
||||
private string _localTempPath;
|
||||
|
||||
public AspNetCoreHostingEnvironment(IOptionsMonitor<HostingSettings> hostingSettings, IWebHostEnvironment webHostEnvironment)
|
||||
public AspNetCoreHostingEnvironment(
|
||||
IOptionsMonitor<HostingSettings> hostingSettings,
|
||||
IOptionsMonitor<WebRoutingSettings> webRoutingSettings,
|
||||
IWebHostEnvironment webHostEnvironment)
|
||||
{
|
||||
_hostingSettings = hostingSettings ?? throw new ArgumentNullException(nameof(hostingSettings));
|
||||
_webRoutingSettings = webRoutingSettings ?? throw new ArgumentNullException(nameof(webRoutingSettings));
|
||||
_webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment));
|
||||
|
||||
SiteName = webHostEnvironment.ApplicationName;
|
||||
ApplicationId = AppDomain.CurrentDomain.Id.ToString();
|
||||
ApplicationPhysicalPath = webHostEnvironment.ContentRootPath;
|
||||
|
||||
IISVersion = new Version(0, 0); // TODO not necessary IIS
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsHosted { get; } = true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Uri ApplicationMainUrl { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string SiteName { get; }
|
||||
|
||||
@@ -39,8 +47,6 @@ namespace Umbraco.Web.Common.AspNetCore
|
||||
/// <inheritdoc/>
|
||||
public string ApplicationPhysicalPath { get; }
|
||||
|
||||
public string ApplicationServerAddress { get; }
|
||||
|
||||
// TODO how to find this, This is a server thing, not application thing.
|
||||
public string ApplicationVirtualPath => _hostingSettings.CurrentValue.ApplicationVirtualPath?.EnsureStartsWith('/') ?? "/";
|
||||
|
||||
@@ -125,6 +131,35 @@ namespace Umbraco.Web.Common.AspNetCore
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
public void EnsureApplicationMainUrl(Uri currentApplicationUrl)
|
||||
{
|
||||
// Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that
|
||||
// it changes the URL to `localhost:80` which actually doesn't work for pinging itself, it only works internally in Azure. The ironic part
|
||||
// about this is that this is here specifically for the slot swap scenario https://issues.umbraco.org/issue/U4-10626
|
||||
|
||||
// see U4-10626 - in some cases we want to reset the application url
|
||||
// (this is a simplified version of what was in 7.x)
|
||||
// note: should this be optional? is it expensive?
|
||||
|
||||
if (currentApplicationUrl is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(_webRoutingSettings.CurrentValue.UmbracoApplicationUrl is null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var change = !_applicationUrls.Contains(currentApplicationUrl);
|
||||
if (change)
|
||||
{
|
||||
_applicationUrls.Add(currentApplicationUrl);
|
||||
|
||||
ApplicationMainUrl = currentApplicationUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -10,42 +11,45 @@ using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler<UmbracoRequestBegin>, INotificationHandler<UmbracoRequestEnd>
|
||||
public class AspNetCoreRequestAccessor : IRequestAccessor, INotificationHandler<UmbracoRequestBegin>
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
private readonly WebRoutingSettings _webRoutingSettings;
|
||||
private readonly ISet<string> _applicationUrls = new HashSet<string>();
|
||||
private Uri _currentApplicationUrl;
|
||||
private object _initLocker = new object();
|
||||
private bool _hasAppUrl = false;
|
||||
private bool _isInit = false;
|
||||
|
||||
public AspNetCoreRequestAccessor(IHttpContextAccessor httpContextAccessor,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AspNetCoreRequestAccessor"/> class.
|
||||
/// </summary>
|
||||
public AspNetCoreRequestAccessor(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IOptions<WebRoutingSettings> webRoutingSettings)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_webRoutingSettings = webRoutingSettings.Value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetRequestValue(string name) => GetFormValue(name) ?? GetQueryStringValue(name);
|
||||
|
||||
public string GetFormValue(string name)
|
||||
private string GetFormValue(string name)
|
||||
{
|
||||
var request = _httpContextAccessor.GetRequiredHttpContext().Request;
|
||||
if (!request.HasFormContentType) return null;
|
||||
return request.Form[name];
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetQueryStringValue(string name) => _httpContextAccessor.GetRequiredHttpContext().Request.Query[name];
|
||||
|
||||
public event EventHandler<UmbracoRequestEventArgs> EndRequest;
|
||||
|
||||
public event EventHandler<RoutableAttemptEventArgs> RouteAttempt;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Uri GetRequestUrl() => _httpContextAccessor.HttpContext != null ? new Uri(_httpContextAccessor.HttpContext.Request.GetEncodedUrl()) : null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Uri GetApplicationUrl()
|
||||
{
|
||||
// Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that
|
||||
@@ -80,17 +84,16 @@ namespace Umbraco.Web.Common.AspNetCore
|
||||
return _currentApplicationUrl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This just initializes the application URL on first request attempt
|
||||
/// TODO: This doesn't belong here, the GetApplicationUrl doesn't belong to IRequestAccessor
|
||||
/// this should be part of middleware not a lazy init based on an INotification
|
||||
/// </summary>
|
||||
public void Handle(UmbracoRequestBegin notification)
|
||||
{
|
||||
var reason = EnsureRoutableOutcome.IsRoutable; //TODO get the correct value here like in UmbracoInjectedModule
|
||||
RouteAttempt?.Invoke(this, new RoutableAttemptEventArgs(reason, _umbracoContextAccessor.UmbracoContext));
|
||||
}
|
||||
|
||||
public void Handle(UmbracoRequestEnd notification)
|
||||
{
|
||||
EndRequest?.Invoke(this, new UmbracoRequestEventArgs(_umbracoContextAccessor.UmbracoContext));
|
||||
}
|
||||
|
||||
|
||||
=> LazyInitializer.EnsureInitialized(ref _hasAppUrl, ref _isInit, ref _initLocker, () =>
|
||||
{
|
||||
GetApplicationUrl();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,17 +51,29 @@ namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_helper != null) return _helper;
|
||||
if (_helper != null)
|
||||
{
|
||||
return _helper;
|
||||
}
|
||||
|
||||
var model = ViewData.Model;
|
||||
TModel model = ViewData.Model;
|
||||
var content = model as IPublishedContent;
|
||||
if (content == null && model is IContentModel)
|
||||
content = ((IContentModel) model).Content;
|
||||
if (content is null && model is IContentModel contentModel)
|
||||
{
|
||||
content = contentModel.Content;
|
||||
}
|
||||
|
||||
if (content is null)
|
||||
{
|
||||
content = UmbracoContext?.PublishedRequest?.PublishedContent;
|
||||
}
|
||||
|
||||
_helper = Context.RequestServices.GetRequiredService<UmbracoHelper>();
|
||||
|
||||
if (content != null)
|
||||
if (!(content is null))
|
||||
{
|
||||
_helper.AssignedContentItem = content;
|
||||
}
|
||||
|
||||
return _helper;
|
||||
}
|
||||
|
||||
20
src/Umbraco.Web.Common/Controllers/ProxyViewDataFeature.cs
Normal file
20
src/Umbraco.Web.Common/Controllers/ProxyViewDataFeature.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
|
||||
namespace Umbraco.Web.Common.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// A request feature to allowing proxying viewdata from one controller to another
|
||||
/// </summary>
|
||||
public sealed class ProxyViewDataFeature
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProxyViewDataFeature"/> class.
|
||||
/// </summary>
|
||||
public ProxyViewDataFeature(ViewDataDictionary viewData) => ViewData = viewData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ViewDataDictionary"/>
|
||||
/// </summary>
|
||||
public ViewDataDictionary ViewData { get; }
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,13 @@ namespace Umbraco.Web.Common.Controllers
|
||||
/// </summary>
|
||||
protected UmbracoRouteValues GetUmbracoRouteValues(ResultExecutingContext context)
|
||||
{
|
||||
if (!context.RouteData.Values.TryGetValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken, out var def))
|
||||
UmbracoRouteValues routeVals = context.HttpContext.Features.Get<UmbracoRouteValues>();
|
||||
if (routeVals == null)
|
||||
{
|
||||
throw new InvalidOperationException($"No route value found with key {Core.Constants.Web.UmbracoRouteDefinitionDataToken}");
|
||||
throw new InvalidOperationException($"No {nameof(UmbracoRouteValues)} feature was found in the HttpContext");
|
||||
}
|
||||
|
||||
return (UmbracoRouteValues)def;
|
||||
return routeVals;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
@@ -71,11 +72,11 @@ namespace Umbraco.Web.Common.Controllers
|
||||
return _umbracoRouteValues;
|
||||
}
|
||||
|
||||
_umbracoRouteValues = HttpContext.GetRouteValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken) as UmbracoRouteValues;
|
||||
_umbracoRouteValues = HttpContext.Features.Get<UmbracoRouteValues>();
|
||||
|
||||
if (_umbracoRouteValues == null)
|
||||
{
|
||||
throw new InvalidOperationException($"No route value found with key {Core.Constants.Web.UmbracoRouteDefinitionDataToken}");
|
||||
throw new InvalidOperationException($"No {nameof(UmbracoRouteValues)} feature was found in the HttpContext");
|
||||
}
|
||||
|
||||
return _umbracoRouteValues;
|
||||
@@ -149,6 +150,20 @@ namespace Umbraco.Web.Common.Controllers
|
||||
break;
|
||||
case UmbracoRouteResult.Success:
|
||||
default:
|
||||
|
||||
// Check if there's a ProxyViewDataFeature in the request.
|
||||
// If there it is means that we are proxying/executing this controller
|
||||
// from another controller and we need to merge it's ViewData with this one
|
||||
// since this one will be empty.
|
||||
ProxyViewDataFeature saveViewData = HttpContext.Features.Get<ProxyViewDataFeature>();
|
||||
if (saveViewData != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> kv in saveViewData.ViewData)
|
||||
{
|
||||
ViewData[kv.Key] = kv.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// continue normally
|
||||
await next();
|
||||
break;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.Common.Controllers
|
||||
{
|
||||
@@ -7,8 +7,9 @@ namespace Umbraco.Web.Common.Controllers
|
||||
/// </summary>
|
||||
public abstract class UmbracoApiController : UmbracoApiControllerBase, IDiscoverable
|
||||
{
|
||||
// TODO: Should this only exist in the back office project? These really are only ever used for the back office AFAIK
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UmbracoApiController"/> class.
|
||||
/// </summary>
|
||||
protected UmbracoApiController()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Authorization;
|
||||
using Umbraco.Web.Common.Filters;
|
||||
using Umbraco.Web.Features;
|
||||
|
||||
namespace Umbraco.Web.Common.Controllers
|
||||
@@ -18,9 +17,10 @@ namespace Umbraco.Web.Common.Controllers
|
||||
[UmbracoApiController]
|
||||
public abstract class UmbracoApiControllerBase : ControllerBase, IUmbracoFeature
|
||||
{
|
||||
// TODO: Should this only exist in the back office project? These really are only ever used for the back office AFAIK
|
||||
|
||||
public UmbracoApiControllerBase()
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UmbracoApiControllerBase"/> class.
|
||||
/// </summary>
|
||||
protected UmbracoApiControllerBase()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,6 @@ namespace Umbraco.Web.Common.DependencyInjection
|
||||
builder.Services.AddUnique<IHttpContextAccessor, HttpContextAccessor>();
|
||||
builder.Services.AddUnique<IRequestAccessor, AspNetCoreRequestAccessor>();
|
||||
builder.AddNotificationHandler<UmbracoRequestBegin, AspNetCoreRequestAccessor>();
|
||||
builder.AddNotificationHandler<UmbracoRequestEnd, AspNetCoreRequestAccessor>();
|
||||
|
||||
// Password hasher
|
||||
builder.Services.AddUnique<IPasswordHasher, AspNetCorePasswordHasher>();
|
||||
@@ -383,9 +382,11 @@ namespace Umbraco.Web.Common.DependencyInjection
|
||||
private static IHostingEnvironment GetTemporaryHostingEnvironment(IWebHostEnvironment webHostEnvironment, IConfiguration config)
|
||||
{
|
||||
var hostingSettings = config.GetSection(Core.Constants.Configuration.ConfigHosting).Get<HostingSettings>() ?? new HostingSettings();
|
||||
var webRoutingSettings = config.GetSection(Core.Constants.Configuration.ConfigWebRouting).Get<WebRoutingSettings>() ?? new WebRoutingSettings();
|
||||
var wrappedHostingSettings = new OptionsMonitorAdapter<HostingSettings>(hostingSettings);
|
||||
var wrappedWebRoutingSettings = new OptionsMonitorAdapter<WebRoutingSettings>(webRoutingSettings);
|
||||
|
||||
return new AspNetCoreHostingEnvironment(wrappedHostingSettings, webHostEnvironment);
|
||||
return new AspNetCoreHostingEnvironment(wrappedHostingSettings,wrappedWebRoutingSettings, webHostEnvironment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Notification raised on each request begin.
|
||||
/// </summary>
|
||||
public class UmbracoRequestBegin : INotification
|
||||
{
|
||||
public UmbracoRequestBegin(HttpContext httpContext)
|
||||
{
|
||||
HttpContext = httpContext;
|
||||
}
|
||||
|
||||
public HttpContext HttpContext { get; }
|
||||
};
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Notification raised on each request end.
|
||||
/// </summary>
|
||||
public class UmbracoRequestEnd : INotification
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UmbracoRequestEnd"/> class.
|
||||
/// </summary>
|
||||
public UmbracoRequestEnd(HttpContext httpContext) => HttpContext = httpContext;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="HttpContext"/>
|
||||
/// </summary>
|
||||
public HttpContext HttpContext { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.Blocks;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Umbraco.Core.Models.Blocks;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class BlockListTemplateExtensions
|
||||
{
|
||||
public const string DefaultFolder = "BlockList/";
|
||||
public const string DefaultTemplate = "Default";
|
||||
public const string DefaultFolder = "blocklist/";
|
||||
public const string DefaultTemplate = "default";
|
||||
|
||||
public static IHtmlContent GetBlockListHtml(this HtmlHelper html, BlockListModel model, string template = DefaultTemplate)
|
||||
public static IHtmlContent GetBlockListHtml(this IHtmlHelper html, BlockListModel model, string template = DefaultTemplate)
|
||||
{
|
||||
if (model?.Count == 0) return new HtmlString(string.Empty);
|
||||
|
||||
@@ -20,11 +20,11 @@ namespace Umbraco.Extensions
|
||||
return html.Partial(view, model);
|
||||
}
|
||||
|
||||
public static IHtmlContent GetBlockListHtml(this HtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) => GetBlockListHtml(html, property?.GetValue() as BlockListModel, template);
|
||||
public static IHtmlContent GetBlockListHtml(this IHtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) => GetBlockListHtml(html, property?.GetValue() as BlockListModel, template);
|
||||
|
||||
public static IHtmlContent GetBlockListHtml(this HtmlHelper html, IPublishedContent contentItem, string propertyAlias) => GetBlockListHtml(html, contentItem, propertyAlias, DefaultTemplate);
|
||||
public static IHtmlContent GetBlockListHtml(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias) => GetBlockListHtml(html, contentItem, propertyAlias, DefaultTemplate);
|
||||
|
||||
public static IHtmlContent GetBlockListHtml(this HtmlHelper html, IPublishedContent contentItem, string propertyAlias, string template)
|
||||
public static IHtmlContent GetBlockListHtml(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias, string template)
|
||||
{
|
||||
if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias));
|
||||
if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias));
|
||||
|
||||
@@ -29,21 +29,20 @@ namespace Umbraco.Web.Common.Extensions
|
||||
var pattern = new StringBuilder(rootSegment);
|
||||
if (!prefixPathSegment.IsNullOrWhiteSpace())
|
||||
{
|
||||
pattern.Append("/").Append(prefixPathSegment);
|
||||
pattern.Append('/').Append(prefixPathSegment);
|
||||
}
|
||||
|
||||
if (includeControllerNameInRoute)
|
||||
{
|
||||
pattern.Append("/").Append(controllerName);
|
||||
pattern.Append('/').Append(controllerName);
|
||||
}
|
||||
|
||||
pattern.Append("/").Append("{action}/{id?}");
|
||||
pattern.Append("/{action}/{id?}");
|
||||
|
||||
var defaults = defaultAction.IsNullOrWhiteSpace()
|
||||
? (object)new { controller = controllerName }
|
||||
: new { controller = controllerName, action = defaultAction };
|
||||
|
||||
|
||||
if (areaName.IsNullOrWhiteSpace())
|
||||
{
|
||||
endpoints.MapControllerRoute(
|
||||
@@ -70,6 +69,7 @@ namespace Umbraco.Web.Common.Extensions
|
||||
/// <summary>
|
||||
/// Used to map Umbraco controllers consistently
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The <see cref="ControllerBase"/> type to route</typeparam>
|
||||
public static void MapUmbracoRoute<T>(
|
||||
this IEndpointRouteBuilder endpoints,
|
||||
string rootSegment,
|
||||
@@ -82,8 +82,9 @@ namespace Umbraco.Web.Common.Extensions
|
||||
=> endpoints.MapUmbracoRoute(typeof(T), rootSegment, areaName, prefixPathSegment, defaultAction, includeControllerNameInRoute, constraints);
|
||||
|
||||
/// <summary>
|
||||
/// Used to map Umbraco api controllers consistently
|
||||
/// Used to map controllers as Umbraco API routes consistently
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The <see cref="ControllerBase"/> type to route</typeparam>
|
||||
public static void MapUmbracoApiRoute<T>(
|
||||
this IEndpointRouteBuilder endpoints,
|
||||
string rootSegment,
|
||||
@@ -95,7 +96,7 @@ namespace Umbraco.Web.Common.Extensions
|
||||
=> endpoints.MapUmbracoApiRoute(typeof(T), rootSegment, areaName, isBackOffice, defaultAction, constraints);
|
||||
|
||||
/// <summary>
|
||||
/// Used to map Umbraco api controllers consistently
|
||||
/// Used to map controllers as Umbraco API routes consistently
|
||||
/// </summary>
|
||||
public static void MapUmbracoApiRoute(
|
||||
this IEndpointRouteBuilder endpoints,
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Extensions
|
||||
var asString = property.GetValue() as string;
|
||||
if (asString != null && string.IsNullOrEmpty(asString)) return new HtmlString(string.Empty);
|
||||
|
||||
var view = "Grid/" + framework;
|
||||
var view = "grid/" + framework;
|
||||
return html.Partial(view, property.GetValue());
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Extensions
|
||||
if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias));
|
||||
if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias));
|
||||
|
||||
var view = "Grid/" + framework;
|
||||
var view = "grid/" + framework;
|
||||
var prop = contentItem.GetProperty(propertyAlias);
|
||||
if (prop == null) throw new InvalidOperationException("No property type found with alias " + propertyAlias);
|
||||
var model = prop.GetValue();
|
||||
@@ -63,7 +63,7 @@ namespace Umbraco.Extensions
|
||||
if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias));
|
||||
if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias));
|
||||
|
||||
var view = "Grid/" + framework;
|
||||
var view = "grid/" + framework;
|
||||
var prop = contentItem.GetProperty(propertyAlias);
|
||||
if (prop == null) throw new InvalidOperationException("No property type found with alias " + propertyAlias);
|
||||
var model = prop.GetValue();
|
||||
@@ -78,7 +78,7 @@ namespace Umbraco.Extensions
|
||||
var asString = property.GetValue() as string;
|
||||
if (asString != null && string.IsNullOrEmpty(asString)) return new HtmlString(string.Empty);
|
||||
|
||||
var view = "Grid/" + framework;
|
||||
var view = "grid/" + framework;
|
||||
return html.Partial(view, property.GetValue());
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Umbraco.Extensions
|
||||
if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias));
|
||||
if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias));
|
||||
|
||||
var view = "Grid/" + framework;
|
||||
var view = "grid/" + framework;
|
||||
var prop = contentItem.GetProperty(propertyAlias);
|
||||
if (prop == null) throw new InvalidOperationException("No property type found with alias " + propertyAlias);
|
||||
var model = prop.GetValue();
|
||||
|
||||
@@ -2,13 +2,15 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using System.Reflection;
|
||||
using Umbraco.Web.Common.Install;
|
||||
using Umbraco.Core.Hosting;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
using Umbraco.Web.Common.Install;
|
||||
using Umbraco.Web.Mvc;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
@@ -17,8 +19,6 @@ namespace Umbraco.Extensions
|
||||
/// <summary>
|
||||
/// Return the back office url if the back office is installed
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetBackOfficeUrl(this LinkGenerator linkGenerator, IHostingEnvironment hostingEnvironment)
|
||||
{
|
||||
|
||||
@@ -26,7 +26,10 @@ namespace Umbraco.Extensions
|
||||
try
|
||||
{
|
||||
backOfficeControllerType = Assembly.Load("Umbraco.Web.BackOffice")?.GetType("Umbraco.Web.BackOffice.Controllers.BackOfficeController");
|
||||
if (backOfficeControllerType == null) return "/"; // this would indicate that the installer is installed without the back office
|
||||
if (backOfficeControllerType == null)
|
||||
{
|
||||
return "/"; // this would indicate that the installer is installed without the back office
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -39,47 +42,33 @@ namespace Umbraco.Extensions
|
||||
/// <summary>
|
||||
/// Returns the URL for the installer
|
||||
/// </summary>
|
||||
/// <param name="linkGenerator"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetInstallerUrl(this LinkGenerator linkGenerator)
|
||||
{
|
||||
return linkGenerator.GetPathByAction(nameof(InstallController.Index), ControllerExtensions.GetControllerName<InstallController>(), new { area = Constants.Web.Mvc.InstallArea });
|
||||
}
|
||||
=> linkGenerator.GetPathByAction(nameof(InstallController.Index), ControllerExtensions.GetControllerName<InstallController>(), new { area = Constants.Web.Mvc.InstallArea });
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URL for the installer api
|
||||
/// </summary>
|
||||
/// <param name="linkGenerator"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetInstallerApiUrl(this LinkGenerator linkGenerator)
|
||||
{
|
||||
return linkGenerator.GetPathByAction(nameof(InstallApiController.GetSetup),
|
||||
=> linkGenerator.GetPathByAction(
|
||||
nameof(InstallApiController.GetSetup),
|
||||
ControllerExtensions.GetControllerName<InstallApiController>(),
|
||||
new { area = Constants.Web.Mvc.InstallArea }).TrimEnd(nameof(InstallApiController.GetSetup));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the Url for a Web Api service
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="actionName"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
/// <typeparam name="T">The <see cref="UmbracoApiControllerBase"/></typeparam>
|
||||
public static string GetUmbracoApiService<T>(this LinkGenerator linkGenerator, string actionName, object id = null)
|
||||
where T : UmbracoApiControllerBase
|
||||
{
|
||||
return linkGenerator.GetUmbracoApiService(actionName, typeof(T), new Dictionary<string, object>()
|
||||
{
|
||||
["id"] = id
|
||||
});
|
||||
}
|
||||
where T : UmbracoApiControllerBase => linkGenerator.GetUmbracoControllerUrl(
|
||||
actionName,
|
||||
typeof(T),
|
||||
new Dictionary<string, object>()
|
||||
{
|
||||
["id"] = id
|
||||
});
|
||||
|
||||
public static string GetUmbracoApiService<T>(this LinkGenerator linkGenerator, string actionName, IDictionary<string, object> values)
|
||||
where T : UmbracoApiControllerBase
|
||||
{
|
||||
return linkGenerator.GetUmbracoApiService(actionName, typeof(T), values);
|
||||
}
|
||||
where T : UmbracoApiControllerBase => linkGenerator.GetUmbracoControllerUrl(actionName, typeof(T), values);
|
||||
|
||||
public static string GetUmbracoApiServiceBaseUrl<T>(this LinkGenerator linkGenerator, Expression<Func<T, object>> methodSelector)
|
||||
where T : UmbracoApiControllerBase
|
||||
@@ -93,66 +82,86 @@ namespace Umbraco.Extensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the Url for a Web Api service
|
||||
/// Return the Url for an Umbraco controller
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="actionName"></param>
|
||||
/// <param name="controllerName"></param>
|
||||
/// <param name="area"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetUmbracoApiService(this LinkGenerator linkGenerator, string actionName, string controllerName, string area, IDictionary<string,object> dict = null)
|
||||
public static string GetUmbracoControllerUrl(this LinkGenerator linkGenerator, string actionName, string controllerName, string area, IDictionary<string, object> dict = null)
|
||||
{
|
||||
if (actionName == null) throw new ArgumentNullException(nameof(actionName));
|
||||
if (string.IsNullOrWhiteSpace(actionName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName));
|
||||
if (controllerName == null) throw new ArgumentNullException(nameof(controllerName));
|
||||
if (string.IsNullOrWhiteSpace(controllerName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(controllerName));
|
||||
if (actionName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(actionName));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(actionName))
|
||||
{
|
||||
throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName));
|
||||
}
|
||||
|
||||
if (controllerName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(controllerName));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(controllerName))
|
||||
{
|
||||
throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(controllerName));
|
||||
}
|
||||
|
||||
if (dict is null)
|
||||
{
|
||||
dict = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!area.IsNullOrWhiteSpace())
|
||||
{
|
||||
dict["area"] = area;
|
||||
}
|
||||
|
||||
|
||||
var values = dict.Aggregate(new ExpandoObject() as IDictionary<string, object>,
|
||||
(a, p) => { a.Add(p.Key, p.Value); return a; });
|
||||
IDictionary<string, object> values = dict.Aggregate(
|
||||
new ExpandoObject() as IDictionary<string, object>,
|
||||
(a, p) =>
|
||||
{
|
||||
a.Add(p.Key, p.Value);
|
||||
return a;
|
||||
});
|
||||
|
||||
return linkGenerator.GetPathByAction(actionName, controllerName, values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the Url for a Web Api service
|
||||
/// Return the Url for an Umbraco controller
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="actionName"></param>
|
||||
/// <param name="apiControllerType"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetUmbracoApiService(this LinkGenerator linkGenerator, string actionName, Type apiControllerType, IDictionary<string,object> values = null)
|
||||
public static string GetUmbracoControllerUrl(this LinkGenerator linkGenerator, string actionName, Type controllerType, IDictionary<string, object> values = null)
|
||||
{
|
||||
if (actionName == null) throw new ArgumentNullException(nameof(actionName));
|
||||
if (string.IsNullOrWhiteSpace(actionName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName));
|
||||
if (apiControllerType == null) throw new ArgumentNullException(nameof(apiControllerType));
|
||||
if (actionName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(actionName));
|
||||
}
|
||||
|
||||
var area = "";
|
||||
if (string.IsNullOrWhiteSpace(actionName))
|
||||
{
|
||||
throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName));
|
||||
}
|
||||
|
||||
if (!typeof(UmbracoApiControllerBase).IsAssignableFrom(apiControllerType))
|
||||
throw new InvalidOperationException($"The controller {apiControllerType} is of type {typeof(UmbracoApiControllerBase)}");
|
||||
if (controllerType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(controllerType));
|
||||
}
|
||||
|
||||
var metaData = PluginController.GetMetadata(apiControllerType);
|
||||
var area = string.Empty;
|
||||
|
||||
if (!typeof(ControllerBase).IsAssignableFrom(controllerType))
|
||||
{
|
||||
throw new InvalidOperationException($"The controller {controllerType} is of type {typeof(ControllerBase)}");
|
||||
}
|
||||
|
||||
PluginControllerMetadata metaData = PluginController.GetMetadata(controllerType);
|
||||
if (metaData.AreaName.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
//set the area to the plugin area
|
||||
// set the area to the plugin area
|
||||
area = metaData.AreaName;
|
||||
}
|
||||
return linkGenerator.GetUmbracoApiService(actionName, ControllerExtensions.GetControllerName(apiControllerType), area, values);
|
||||
|
||||
return linkGenerator.GetUmbracoControllerUrl(actionName, ControllerExtensions.GetControllerName(controllerType), area, values);
|
||||
}
|
||||
|
||||
public static string GetUmbracoApiService<T>(this LinkGenerator linkGenerator, Expression<Func<T, object>> methodSelector)
|
||||
@@ -170,6 +179,7 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
return linkGenerator.GetUmbracoApiService<T>(method.Name);
|
||||
}
|
||||
|
||||
return linkGenerator.GetUmbracoApiService<T>(method.Name, methodParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace Umbraco.Web.Common.Localization
|
||||
/// <inheritdoc/>
|
||||
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
|
||||
{
|
||||
if (httpContext.GetRouteValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken) is UmbracoRouteValues routeValues)
|
||||
UmbracoRouteValues routeValues = httpContext.Features.Get<UmbracoRouteValues>();
|
||||
if (routeValues != null)
|
||||
{
|
||||
string culture = routeValues.PublishedRequest?.Culture;
|
||||
if (culture != null)
|
||||
|
||||
@@ -17,6 +17,7 @@ using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.Macros;
|
||||
using static Umbraco.Core.Constants.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Common.Macros
|
||||
{
|
||||
@@ -87,8 +88,8 @@ namespace Umbraco.Web.Common.Macros
|
||||
var httpContext = _httpContextAccessor.GetRequiredHttpContext();
|
||||
//var umbCtx = _getUmbracoContext();
|
||||
var routeVals = new RouteData();
|
||||
routeVals.Values.Add("controller", "PartialViewMacro");
|
||||
routeVals.Values.Add("action", "Index");
|
||||
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);
|
||||
|
||||
@@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.Common.Profiler;
|
||||
@@ -36,6 +37,7 @@ namespace Umbraco.Web.Common.Middleware
|
||||
private readonly IBackOfficeSecurityFactory _backofficeSecurityFactory;
|
||||
private readonly PublishedSnapshotServiceEventHandler _publishedSnapshotServiceEventHandler;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly WebProfiler _profiler;
|
||||
private static bool s_cacheInitialized = false;
|
||||
private static bool s_cacheInitializedFlag = false;
|
||||
@@ -51,7 +53,8 @@ namespace Umbraco.Web.Common.Middleware
|
||||
IBackOfficeSecurityFactory backofficeSecurityFactory,
|
||||
PublishedSnapshotServiceEventHandler publishedSnapshotServiceEventHandler,
|
||||
IEventAggregator eventAggregator,
|
||||
IProfiler profiler)
|
||||
IProfiler profiler,
|
||||
IHostingEnvironment hostingEnvironment)
|
||||
{
|
||||
_logger = logger;
|
||||
_umbracoContextFactory = umbracoContextFactory;
|
||||
@@ -59,6 +62,7 @@ namespace Umbraco.Web.Common.Middleware
|
||||
_backofficeSecurityFactory = backofficeSecurityFactory;
|
||||
_publishedSnapshotServiceEventHandler = publishedSnapshotServiceEventHandler;
|
||||
_eventAggregator = eventAggregator;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
_profiler = profiler as WebProfiler; // Ignore if not a WebProfiler
|
||||
}
|
||||
|
||||
@@ -81,6 +85,10 @@ namespace Umbraco.Web.Common.Middleware
|
||||
_backofficeSecurityFactory.EnsureBackOfficeSecurity(); // Needs to be before UmbracoContext, TODO: Why?
|
||||
UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext();
|
||||
|
||||
Uri currentApplicationUrl = GetApplicationUrlFromCurrentRequest(context.Request);
|
||||
_hostingEnvironment.EnsureApplicationMainUrl(currentApplicationUrl);
|
||||
|
||||
|
||||
bool isFrontEndRequest = umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest();
|
||||
|
||||
var pathAndQuery = context.Request.GetEncodedPathAndQuery();
|
||||
@@ -95,7 +103,7 @@ namespace Umbraco.Web.Common.Middleware
|
||||
|
||||
try
|
||||
{
|
||||
await _eventAggregator.PublishAsync(new UmbracoRequestBegin(context));
|
||||
await _eventAggregator.PublishAsync(new UmbracoRequestBegin(umbracoContextReference.UmbracoContext));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -111,7 +119,7 @@ namespace Umbraco.Web.Common.Middleware
|
||||
}
|
||||
finally
|
||||
{
|
||||
await _eventAggregator.PublishAsync(new UmbracoRequestEnd(context));
|
||||
await _eventAggregator.PublishAsync(new UmbracoRequestEnd(umbracoContextReference.UmbracoContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,7 +127,7 @@ namespace Umbraco.Web.Common.Middleware
|
||||
{
|
||||
if (isFrontEndRequest)
|
||||
{
|
||||
LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache);
|
||||
LogHttpRequest.TryGetCurrentHttpRequestId(out Guid httpRequestId, _requestCache);
|
||||
_logger.LogTrace("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, pathAndQuery, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds);
|
||||
}
|
||||
|
||||
@@ -138,6 +146,18 @@ namespace Umbraco.Web.Common.Middleware
|
||||
_profiler?.UmbracoApplicationEndRequest(context);
|
||||
}
|
||||
|
||||
private Uri GetApplicationUrlFromCurrentRequest(HttpRequest request)
|
||||
{
|
||||
// We only consider GET and POST.
|
||||
// Especially the DEBUG sent when debugging the application is annoying because it uses http, even when the https is available.
|
||||
if (request.Method == "GET" || request.Method == "POST")
|
||||
{
|
||||
return new Uri($"{request.Scheme}://{request.Host}{request.PathBase}", UriKind.Absolute);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request
|
||||
/// </summary>
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace Umbraco.Web.Common.ModelBinders
|
||||
// only IPublishedContent will ever exist in the request so when this model binder is used as an IModelBinder
|
||||
// in the aspnet pipeline it will really only support converting from IPublishedContent which is contained
|
||||
// in the UmbracoRouteValues --> IContentModel
|
||||
if (!bindingContext.ActionContext.RouteData.Values.TryGetValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken, out var source)
|
||||
|| !(source is UmbracoRouteValues umbracoRouteValues))
|
||||
UmbracoRouteValues umbracoRouteValues = bindingContext.HttpContext.Features.Get<UmbracoRouteValues>();
|
||||
if (umbracoRouteValues is null)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
@@ -21,29 +22,25 @@ namespace Umbraco.Web.Common.Routing
|
||||
/// </summary>
|
||||
public UmbracoRouteValues(
|
||||
IPublishedRequest publishedRequest,
|
||||
string controllerName = null,
|
||||
Type controllerType = null,
|
||||
string actionName = DefaultActionName,
|
||||
ControllerActionDescriptor controllerActionDescriptor,
|
||||
string templateName = null,
|
||||
bool hasHijackedRoute = false)
|
||||
{
|
||||
ControllerName = controllerName ?? ControllerExtensions.GetControllerName<RenderController>();
|
||||
ControllerType = controllerType ?? typeof(RenderController);
|
||||
PublishedRequest = publishedRequest;
|
||||
ControllerActionDescriptor = controllerActionDescriptor;
|
||||
HasHijackedRoute = hasHijackedRoute;
|
||||
ActionName = actionName;
|
||||
TemplateName = templateName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the controller name
|
||||
/// </summary>
|
||||
public string ControllerName { get; }
|
||||
public string ControllerName => ControllerActionDescriptor.ControllerName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the action name
|
||||
/// </summary>
|
||||
public string ActionName { get; }
|
||||
public string ActionName => ControllerActionDescriptor.ActionName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template name
|
||||
@@ -51,9 +48,14 @@ namespace Umbraco.Web.Common.Routing
|
||||
public string TemplateName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Controller type found for routing to
|
||||
/// Gets the controller type
|
||||
/// </summary>
|
||||
public Type ControllerType { get; }
|
||||
public Type ControllerType => ControllerActionDescriptor.ControllerTypeInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Controller descriptor found for routing to
|
||||
/// </summary>
|
||||
public ControllerActionDescriptor ControllerActionDescriptor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IPublishedRequest"/>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
@@ -12,64 +13,80 @@ namespace Umbraco.Web.Common.Security
|
||||
{
|
||||
public class EncryptionHelper
|
||||
{
|
||||
// TODO: Decide if these belong here... I don't think so since this all has to do with surface controller routes
|
||||
// could also just be injected too....
|
||||
|
||||
private static IDataProtector CreateDataProtector(IDataProtectionProvider dataProtectionProvider)
|
||||
{
|
||||
return dataProtectionProvider.CreateProtector(nameof(EncryptionHelper));
|
||||
}
|
||||
=> dataProtectionProvider.CreateProtector(nameof(EncryptionHelper));
|
||||
|
||||
public static string Decrypt(string encryptedString, IDataProtectionProvider dataProtectionProvider)
|
||||
{
|
||||
return CreateDataProtector(dataProtectionProvider).Unprotect(encryptedString);
|
||||
}
|
||||
=> CreateDataProtector(dataProtectionProvider).Unprotect(encryptedString);
|
||||
|
||||
public static string Encrypt(string plainString, IDataProtectionProvider dataProtectionProvider)
|
||||
{
|
||||
return CreateDataProtector(dataProtectionProvider).Protect(plainString);
|
||||
}
|
||||
=> CreateDataProtector(dataProtectionProvider).Protect(plainString);
|
||||
|
||||
/// <summary>
|
||||
/// This is used in methods like BeginUmbracoForm and SurfaceAction to generate an encrypted string which gets submitted in a request for which
|
||||
/// Umbraco can decrypt during the routing process in order to delegate the request to a specific MVC Controller.
|
||||
/// </summary>
|
||||
/// <param name="dataProtectionProvider"></param>
|
||||
/// <param name="controllerName"></param>
|
||||
/// <param name="controllerAction"></param>
|
||||
/// <param name="area"></param>
|
||||
/// <param name="additionalRouteVals"></param>
|
||||
/// <returns></returns>
|
||||
public static string CreateEncryptedRouteString(IDataProtectionProvider dataProtectionProvider, string controllerName, string controllerAction, string area, object additionalRouteVals = null)
|
||||
{
|
||||
if (dataProtectionProvider == null) throw new ArgumentNullException(nameof(dataProtectionProvider));
|
||||
if (controllerName == null) throw new ArgumentNullException(nameof(controllerName));
|
||||
if (string.IsNullOrEmpty(controllerName)) throw new ArgumentException("Value can't be empty.", nameof(controllerName));
|
||||
if (controllerAction == null) throw new ArgumentNullException(nameof(controllerAction));
|
||||
if (string.IsNullOrEmpty(controllerAction)) throw new ArgumentException("Value can't be empty.", nameof(controllerAction));
|
||||
if (area == null) throw new ArgumentNullException(nameof(area));
|
||||
if (dataProtectionProvider is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dataProtectionProvider));
|
||||
}
|
||||
|
||||
//need to create a params string as Base64 to put into our hidden field to use during the routes
|
||||
if (string.IsNullOrEmpty(controllerName))
|
||||
{
|
||||
throw new ArgumentException($"'{nameof(controllerName)}' cannot be null or empty.", nameof(controllerName));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(controllerAction))
|
||||
{
|
||||
throw new ArgumentException($"'{nameof(controllerAction)}' cannot be null or empty.", nameof(controllerAction));
|
||||
}
|
||||
|
||||
if (area is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(area));
|
||||
}
|
||||
|
||||
// need to create a params string as Base64 to put into our hidden field to use during the routes
|
||||
var surfaceRouteParams = $"{ViewConstants.ReservedAdditionalKeys.Controller}={WebUtility.UrlEncode(controllerName)}&{ViewConstants.ReservedAdditionalKeys.Action}={WebUtility.UrlEncode(controllerAction)}&{ViewConstants.ReservedAdditionalKeys.Area}={area}";
|
||||
|
||||
//checking if the additional route values is already a dictionary and convert to querystring
|
||||
// checking if the additional route values is already a dictionary and convert to querystring
|
||||
string additionalRouteValsAsQuery;
|
||||
if (additionalRouteVals != null)
|
||||
{
|
||||
if (additionalRouteVals is Dictionary<string, object> additionalRouteValsAsDictionary)
|
||||
{
|
||||
additionalRouteValsAsQuery = additionalRouteValsAsDictionary.ToQueryString();
|
||||
}
|
||||
else
|
||||
{
|
||||
additionalRouteValsAsQuery = additionalRouteVals.ToDictionary<object>().ToQueryString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
additionalRouteValsAsQuery = null;
|
||||
}
|
||||
|
||||
if (additionalRouteValsAsQuery.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
surfaceRouteParams += "&" + additionalRouteValsAsQuery;
|
||||
}
|
||||
|
||||
return Encrypt(surfaceRouteParams, dataProtectionProvider);
|
||||
}
|
||||
|
||||
public static bool DecryptAndValidateEncryptedRouteString(IDataProtectionProvider dataProtectionProvider, string encryptedString, out IDictionary<string, string> parts)
|
||||
{
|
||||
if (dataProtectionProvider == null) throw new ArgumentNullException(nameof(dataProtectionProvider));
|
||||
if (dataProtectionProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dataProtectionProvider));
|
||||
}
|
||||
|
||||
string decryptedString;
|
||||
try
|
||||
{
|
||||
@@ -81,22 +98,32 @@ namespace Umbraco.Web.Common.Security
|
||||
parts = null;
|
||||
return false;
|
||||
}
|
||||
var parsedQueryString = HttpUtility.ParseQueryString(decryptedString);
|
||||
|
||||
NameValueCollection parsedQueryString = HttpUtility.ParseQueryString(decryptedString);
|
||||
parts = new Dictionary<string, string>();
|
||||
foreach (var key in parsedQueryString.AllKeys)
|
||||
{
|
||||
parts[key] = parsedQueryString[key];
|
||||
}
|
||||
//validate all required keys exist
|
||||
//the controller
|
||||
|
||||
// validate all required keys exist
|
||||
// the controller
|
||||
if (parts.All(x => x.Key != ViewConstants.ReservedAdditionalKeys.Controller))
|
||||
{
|
||||
return false;
|
||||
//the action
|
||||
}
|
||||
|
||||
// the action
|
||||
if (parts.All(x => x.Key != ViewConstants.ReservedAdditionalKeys.Action))
|
||||
{
|
||||
return false;
|
||||
//the area
|
||||
}
|
||||
|
||||
// the area
|
||||
if (parts.All(x => x.Key != ViewConstants.ReservedAdditionalKeys.Area))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user