Gets auto-routing back office api controllers working, lots of notes
This commit is contained in:
@@ -94,7 +94,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <para>Enables support for MVC, WebAPI, but *not* per-request scope. This is used early in the boot
|
||||
/// process, where anything "scoped" should not be linked to a web request.</para>
|
||||
/// </remarks>
|
||||
void ConfigureForWeb();
|
||||
void ConfigureForWeb(); // TODO: Unsure if we need this anymore
|
||||
|
||||
/// <summary>
|
||||
/// Creates the factory.
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
// TODO: we don't really use this, it is nice to have the treecontroller, attribute and ApplicationTree streamlined to implement this but it's not used
|
||||
//leave as internal for now, maybe we'll use in the future, means we could pass around ITree
|
||||
// leave as internal for now, maybe we'll use in the future, means we could pass around ITree
|
||||
// TODO: We should make this a thing, a tree should just be an interface *not* a controller
|
||||
internal interface ITree
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Umbraco.Tests.Integration.Implementations
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Connection.RemoteIpAddress = IPAddress.Parse("127.0.0.1");
|
||||
_httpContextAccessor = Mock.Of<IHttpContextAccessor>(x => x.HttpContext == httpContext);
|
||||
_ipResolver = new AspNetIpResolver(_httpContextAccessor);
|
||||
_ipResolver = new AspNetCoreIpResolver(_httpContextAccessor);
|
||||
|
||||
var hostEnvironment = new Mock<IWebHostEnvironment>();
|
||||
hostEnvironment.Setup(x => x.ApplicationName).Returns("UmbracoIntegrationTests");
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Filters;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
[Area(Umbraco.Core.Constants.Web.Mvc.BackOfficeArea)]
|
||||
[Area(Constants.Web.Mvc.BackOfficeArea)] // TODO: Maybe this could be applied with our Application Model conventions
|
||||
//[ValidationFilter] // TODO: I don't actually think this is required with our custom Application Model conventions applied
|
||||
[TypeFilter(typeof(AngularJsonOnlyConfigurationAttribute))]
|
||||
[IsBackOffice]
|
||||
[TypeFilter(typeof(AngularJsonOnlyConfigurationAttribute))] // TODO: This could be applied with our Application Model conventions
|
||||
[IsBackOffice] // TODO: This could be applied with our Application Model conventions
|
||||
public class AuthenticationController : ControllerBase
|
||||
{
|
||||
// TODO: We need to import the logic from Umbraco.Web.Editors.AuthenticationController and it should not be an auto-routed api controller
|
||||
|
||||
@@ -3,23 +3,34 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Web.BackOffice.Controllers;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
using Umbraco.Web.Common.Routing;
|
||||
using Umbraco.Web.WebApi;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates routes for the back office area
|
||||
/// </summary>
|
||||
public class BackOfficeAreaRoutes : IAreaRoutes
|
||||
{
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly string _umbracoAreaPathSegment;
|
||||
private readonly UmbracoApiControllerTypeCollection _apiControllers;
|
||||
private readonly string _umbracoPathSegment;
|
||||
|
||||
public BackOfficeAreaRoutes(IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IRuntimeState runtimeState)
|
||||
public BackOfficeAreaRoutes(
|
||||
IGlobalSettings globalSettings,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IRuntimeState runtimeState,
|
||||
UmbracoApiControllerTypeCollection apiControllers)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
_runtimeState = runtimeState;
|
||||
_umbracoAreaPathSegment = _globalSettings.GetUmbracoMvcArea(_hostingEnvironment);
|
||||
_apiControllers = apiControllers;
|
||||
_umbracoPathSegment = _globalSettings.GetUmbracoMvcArea(_hostingEnvironment);
|
||||
}
|
||||
|
||||
public void CreateRoutes(IEndpointRouteBuilder endpoints)
|
||||
@@ -36,7 +47,7 @@ namespace Umbraco.Web.BackOffice.Routing
|
||||
case RuntimeLevel.Run:
|
||||
|
||||
MapMinimalBackOffice(endpoints);
|
||||
endpoints.MapUmbracoRoute<PreviewController>(_umbracoAreaPathSegment, Constants.Web.Mvc.BackOfficeArea, "preview");
|
||||
endpoints.MapUmbracoRoute<PreviewController>(_umbracoPathSegment, Constants.Web.Mvc.BackOfficeArea, "preview");
|
||||
AutoRouteBackOfficeControllers(endpoints);
|
||||
|
||||
break;
|
||||
@@ -53,7 +64,7 @@ namespace Umbraco.Web.BackOffice.Routing
|
||||
/// <param name="endpoints"></param>
|
||||
private void MapMinimalBackOffice(IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
endpoints.MapUmbracoRoute<BackOfficeController>(_umbracoAreaPathSegment, Constants.Web.Mvc.BackOfficeArea,
|
||||
endpoints.MapUmbracoRoute<BackOfficeController>(_umbracoPathSegment, Constants.Web.Mvc.BackOfficeArea,
|
||||
string.Empty,
|
||||
"Default",
|
||||
constraints:
|
||||
@@ -66,7 +77,7 @@ namespace Umbraco.Web.BackOffice.Routing
|
||||
id = @"[a-zA-Z]*"
|
||||
});
|
||||
|
||||
endpoints.MapUmbracoRoute<AuthenticationController>(_umbracoAreaPathSegment, Constants.Web.Mvc.BackOfficeArea, true);
|
||||
endpoints.MapUmbracoApiRoute<AuthenticationController>(_umbracoPathSegment, Constants.Web.Mvc.BackOfficeArea, true, defaultAction: string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,7 +85,24 @@ namespace Umbraco.Web.BackOffice.Routing
|
||||
/// </summary>
|
||||
private void AutoRouteBackOfficeControllers(IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
// TODO: We could investigate dynamically routing plugin controllers so we don't have to eagerly type scan for them,
|
||||
// it would probably work well, see https://www.strathweb.com/2019/08/dynamic-controller-routing-in-asp-net-core-3-0/
|
||||
// will probably be what we use for front-end routing too. BTW the orig article about migrating from IRouter to endpoint
|
||||
// routing for things like a CMS is here https://github.com/dotnet/aspnetcore/issues/4221
|
||||
|
||||
foreach (var controller in _apiControllers)
|
||||
{
|
||||
// exclude front-end api controllers
|
||||
var meta = PluginController.GetMetadata(controller);
|
||||
if (!meta.IsBackOffice) continue;
|
||||
|
||||
endpoints.MapUmbracoApiRoute(
|
||||
meta.ControllerType,
|
||||
_umbracoPathSegment,
|
||||
meta.AreaName,
|
||||
true,
|
||||
defaultAction: string.Empty); // no default action (this is what we had before)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Umbraco.Core;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.BackOffice.Routing;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Runtime
|
||||
|
||||
@@ -3,11 +3,11 @@ using Umbraco.Net;
|
||||
|
||||
namespace Umbraco.Web.Common.AspNetCore
|
||||
{
|
||||
public class AspNetIpResolver : IIpResolver
|
||||
public class AspNetCoreIpResolver : IIpResolver
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public AspNetIpResolver(IHttpContextAccessor httpContextAccessor)
|
||||
public AspNetCoreIpResolver(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Web.Common.Attributes
|
||||
{
|
||||
@@ -8,6 +9,6 @@ namespace Umbraco.Web.Common.Attributes
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class IsBackOfficeAttribute : Attribute
|
||||
{
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Web.Common.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a controller is a plugin controller and should be routed to its own area.
|
||||
/// Indicates that a controller is a plugin controller and will be routed to its own area.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class PluginControllerAttribute : Attribute
|
||||
public class PluginControllerAttribute : AreaAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginControllerAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="areaName"></param>
|
||||
public PluginControllerAttribute(string areaName)
|
||||
public PluginControllerAttribute(string areaName) : base(areaName)
|
||||
{
|
||||
// validate this, only letters and digits allowed.
|
||||
if (areaName.Any(c => !char.IsLetterOrDigit(c)))
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Umbraco.Web.Common.Controllers
|
||||
/// </summary>
|
||||
/// <param name="controllerType">The controller type.</param>
|
||||
/// <returns>Metadata for the controller type.</returns>
|
||||
internal static PluginControllerMetadata GetMetadata(Type controllerType)
|
||||
public static PluginControllerMetadata GetMetadata(Type controllerType)
|
||||
{
|
||||
return MetadataStorage.GetOrAdd(controllerType, type =>
|
||||
{
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace Umbraco.Web.Common.Controllers
|
||||
/// <para>These controllers are NOT auto-routed.</para>
|
||||
/// <para>The base class is <see cref="ControllerBase"/> which are netcore API controllers without any view support</para>
|
||||
/// </remarks>
|
||||
[FeatureAuthorize]
|
||||
[TypeFilter(typeof(HttpResponseExceptionFilter))]
|
||||
[FeatureAuthorize] // TODO: This could be part of our conventions
|
||||
[TypeFilter(typeof(HttpResponseExceptionFilter))] // TODO: This could be part of our conventions
|
||||
[UmbracoApiController]
|
||||
public abstract class UmbracoApiControllerBase : ControllerBase, IUmbracoFeature
|
||||
{
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Web.WebApi;
|
||||
|
||||
namespace Umbraco.Web.Common.Controllers
|
||||
{
|
||||
public class UmbracoApiControllerTypeCollectionBuilder : TypeCollectionBuilderBase<UmbracoApiControllerTypeCollectionBuilder, UmbracoApiControllerTypeCollection, UmbracoApiController>
|
||||
{
|
||||
protected override UmbracoApiControllerTypeCollectionBuilder This => this;
|
||||
}
|
||||
}
|
||||
17
src/Umbraco.Web.Common/Extensions/TypeLoaderExtensions.cs
Normal file
17
src/Umbraco.Web.Common/Extensions/TypeLoaderExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class TypeLoaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all types implementing <see cref="UmbracoApiController"/>.
|
||||
/// </summary>
|
||||
public static IEnumerable<Type> GetUmbracoApiControllers(this TypeLoader typeLoader)
|
||||
=> typeLoader.GetTypes<UmbracoApiController>();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.Common.Install
|
||||
{
|
||||
public class InstallerComposer : IComposer
|
||||
{
|
||||
public void Compose(Composition composition)
|
||||
{
|
||||
composition.RegisterUnique<InstallAreaRoutes>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using NUglify.Helpers;
|
||||
using System;
|
||||
using System.Text;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
@@ -9,6 +10,64 @@ namespace Umbraco.Web.Common.Routing
|
||||
{
|
||||
public static class EndpointRouteBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to map Umbraco controllers consistently
|
||||
/// </summary>
|
||||
/// <param name="endpoints"></param>
|
||||
/// <param name="controllerType"></param>
|
||||
/// <param name="rootSegment"></param>
|
||||
/// <param name="areaName"></param>
|
||||
/// <param name="prefixPathSegment"></param>
|
||||
/// <param name="defaultAction"></param>
|
||||
/// <param name="includeControllerNameInRoute"></param>
|
||||
/// <param name="constraints"></param>
|
||||
public static void MapUmbracoRoute(
|
||||
this IEndpointRouteBuilder endpoints,
|
||||
Type controllerType,
|
||||
string rootSegment,
|
||||
string areaName,
|
||||
string prefixPathSegment,
|
||||
string defaultAction = "Index",
|
||||
bool includeControllerNameInRoute = true,
|
||||
object constraints = null)
|
||||
{
|
||||
var controllerName = ControllerExtensions.GetControllerName(controllerType);
|
||||
|
||||
// build the route pattern
|
||||
var pattern = new StringBuilder(rootSegment);
|
||||
if (!prefixPathSegment.IsNullOrWhiteSpace())
|
||||
pattern.Append("/").Append(prefixPathSegment);
|
||||
if (includeControllerNameInRoute)
|
||||
pattern.Append("/").Append(controllerName);
|
||||
pattern.Append("/").Append("{action}/{id?}");
|
||||
|
||||
var defaults = defaultAction.IsNullOrWhiteSpace()
|
||||
? (object) new { controller = controllerName }
|
||||
: new { controller = controllerName, action = defaultAction };
|
||||
|
||||
|
||||
if (areaName.IsNullOrWhiteSpace())
|
||||
{
|
||||
endpoints.MapControllerRoute(
|
||||
// named consistently
|
||||
$"umbraco-{areaName}-{controllerName}".ToLowerInvariant(),
|
||||
pattern.ToString().ToLowerInvariant(),
|
||||
defaults,
|
||||
constraints);
|
||||
}
|
||||
else
|
||||
{
|
||||
endpoints.MapAreaControllerRoute(
|
||||
// named consistently
|
||||
$"umbraco-{areaName}-{controllerName}".ToLowerInvariant(),
|
||||
areaName,
|
||||
pattern.ToString().ToLowerInvariant(),
|
||||
defaults,
|
||||
constraints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to map Umbraco controllers consistently
|
||||
/// </summary>
|
||||
@@ -28,43 +87,49 @@ namespace Umbraco.Web.Common.Routing
|
||||
bool includeControllerNameInRoute = true,
|
||||
object constraints = null)
|
||||
where T : ControllerBase
|
||||
{
|
||||
var controllerName = ControllerExtensions.GetControllerName<T>();
|
||||
|
||||
// build the route pattern
|
||||
var pattern = new StringBuilder(rootSegment);
|
||||
if (!prefixPathSegment.IsNullOrWhiteSpace())
|
||||
pattern.Append("/").Append(prefixPathSegment);
|
||||
if (includeControllerNameInRoute)
|
||||
pattern.Append("/").Append(controllerName);
|
||||
pattern.Append("/").Append("{action}/{id?}");
|
||||
|
||||
endpoints.MapAreaControllerRoute(
|
||||
// named consistently
|
||||
$"umbraco-{areaName}-{controllerName}".ToLowerInvariant(),
|
||||
areaName,
|
||||
pattern.ToString().ToLowerInvariant(),
|
||||
new { controller = controllerName, action = defaultAction },
|
||||
constraints);
|
||||
}
|
||||
=> endpoints.MapUmbracoRoute(typeof(T), rootSegment, areaName, prefixPathSegment, defaultAction, includeControllerNameInRoute, constraints);
|
||||
|
||||
/// <summary>
|
||||
/// Used to map Umbraco controllers consistently
|
||||
/// Used to map Umbraco api controllers consistently
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="endpoints"></param>
|
||||
/// <param name="rootPathSegment"></param>
|
||||
/// <param name="rootSegment"></param>
|
||||
/// <param name="areaName"></param>
|
||||
/// <param name="isBackOffice"></param>
|
||||
/// <param name="isBackOffice">If the route is a back office route</param>
|
||||
/// <param name="constraints"></param>
|
||||
public static void MapUmbracoRoute<T>(
|
||||
public static void MapUmbracoApiRoute<T>(
|
||||
this IEndpointRouteBuilder endpoints,
|
||||
string rootPathSegment,
|
||||
string rootSegment,
|
||||
string areaName,
|
||||
bool isBackOffice,
|
||||
string defaultAction = "Index",
|
||||
object constraints = null)
|
||||
where T : ControllerBase
|
||||
=> endpoints.MapUmbracoRoute<T>(rootPathSegment, areaName, isBackOffice ? "BackOffice" : "Api", defaultAction, true, constraints);
|
||||
=> endpoints.MapUmbracoRoute(typeof(T), rootSegment, areaName, isBackOffice ? "BackOffice/Api" : "Api", defaultAction, true, constraints);
|
||||
|
||||
/// <summary>
|
||||
/// Used to map Umbraco api controllers consistently
|
||||
/// </summary>
|
||||
/// <param name="endpoints"></param>
|
||||
/// <param name="controllerType"></param>
|
||||
/// <param name="rootSegment"></param>
|
||||
/// <param name="areaName"></param>
|
||||
/// <param name="isBackOffice">If the route is a back office route</param>
|
||||
/// <param name="defaultAction"></param>
|
||||
/// <param name="constraints"></param>
|
||||
public static void MapUmbracoApiRoute(
|
||||
this IEndpointRouteBuilder endpoints,
|
||||
Type controllerType,
|
||||
string rootSegment,
|
||||
string areaName,
|
||||
bool isBackOffice,
|
||||
string defaultAction = "Index",
|
||||
object constraints = null)
|
||||
=> endpoints.MapUmbracoRoute(controllerType, rootSegment, areaName,
|
||||
isBackOffice
|
||||
? (areaName.IsNullOrWhiteSpace() ? "BackOffice/Api" : $"BackOffice/{areaName}")
|
||||
: (areaName.IsNullOrWhiteSpace() ? "Api" : areaName),
|
||||
defaultAction, true, constraints);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ using Umbraco.Web.Macros;
|
||||
using Umbraco.Core.Diagnostics;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Common.Profiler;
|
||||
using Umbraco.Web.Common.Install;
|
||||
using Umbraco.Extensions;
|
||||
using System.Linq;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime
|
||||
{
|
||||
@@ -40,12 +44,12 @@ namespace Umbraco.Web.Common.Runtime
|
||||
// The umbraco request lifetime
|
||||
composition.RegisterMultipleUnique<IUmbracoRequestLifetime, IUmbracoRequestLifetimeManager, UmbracoRequestLifetime>();
|
||||
|
||||
|
||||
//Password hasher
|
||||
composition.RegisterUnique<IPasswordHasher, AspNetCorePasswordHasher>();
|
||||
|
||||
|
||||
composition.RegisterUnique<ICookieManager, AspNetCoreCookieManager>();
|
||||
composition.Register<IIpResolver, AspNetCoreIpResolver>();
|
||||
composition.RegisterUnique<IUserAgentProvider, AspNetCoreUserAgentProvider>();
|
||||
|
||||
composition.RegisterMultipleUnique<ISessionIdResolver, ISessionManager, AspNetCoreSessionManager>();
|
||||
@@ -67,6 +71,12 @@ namespace Umbraco.Web.Common.Runtime
|
||||
//it still needs to use the install controller so we can't do that
|
||||
composition.ComposeInstaller();
|
||||
|
||||
var umbracoApiControllerTypes = composition.TypeLoader.GetUmbracoApiControllers().ToList();
|
||||
composition.WithCollectionBuilder<UmbracoApiControllerTypeCollectionBuilder>()
|
||||
.Add(umbracoApiControllerTypes);
|
||||
|
||||
composition.RegisterUnique<InstallAreaRoutes>();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
|
||||
namespace Umbraco.Web.UI.NetCore.Controllers
|
||||
{
|
||||
[PluginController("Test")]
|
||||
[IsBackOffice]
|
||||
public class TestBackOfficeUmbracoApiController : UmbracoApiController
|
||||
{
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return Content("hello world");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,14 @@ namespace Umbraco.Web.UI.BackOffice
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
{
|
||||
// TODO: We will need to decide on if we want to use the ServiceBasedControllerActivator to create our controllers
|
||||
// or use the default IControllerActivator: DefaultControllerActivator (which doesn't directly use the container to resolve controllers)
|
||||
// This will affect whether we need to explicitly register controllers in the container like we do today in v8.
|
||||
// What we absolutely must do though is make sure we explicitly opt-in to using one or the other *always* for our controllers instead of
|
||||
// relying on a global configuration set by a user since if a custom IControllerActivator is used for our own controllers we may not
|
||||
// guarantee it will work. And then... is that even possible?
|
||||
|
||||
services.AddUmbracoConfiguration(_config);
|
||||
services.AddUmbracoCore(_env, out var factory);
|
||||
services.AddUmbracoWebComponents();
|
||||
|
||||
@@ -3,9 +3,8 @@ using System.Linq;
|
||||
|
||||
namespace Umbraco.Web.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a controller is a plugin tree controller and should be routed to its own area.
|
||||
/// </summary>
|
||||
// TODO: This has been moved to netcore so can be removed when ready
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
public class PluginControllerAttribute : Attribute
|
||||
{
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
using System.Linq;
|
||||
using System.Web.Security;
|
||||
using Examine;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Install;
|
||||
using Umbraco.Core.Runtime;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing.CompositionExtensions;
|
||||
using Umbraco.Web.Hosting;
|
||||
using Umbraco.Web.Install;
|
||||
using Umbraco.Web.Macros;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
@@ -22,12 +16,6 @@ using Umbraco.Web.Security.Providers;
|
||||
using Umbraco.Web.SignalR;
|
||||
using Umbraco.Web.Templates;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Web.AspNet;
|
||||
using Umbraco.Core.Diagnostics;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Logging;
|
||||
|
||||
namespace Umbraco.Web.Runtime
|
||||
{
|
||||
@@ -41,28 +29,9 @@ namespace Umbraco.Web.Runtime
|
||||
base.Compose(composition);
|
||||
|
||||
composition.Register<UmbracoInjectedModule>();
|
||||
composition.Register<IIpResolver, AspNetIpResolver>();
|
||||
|
||||
composition.Register<IUserAgentProvider, AspNetUserAgentProvider>();
|
||||
|
||||
|
||||
composition.Register<IRequestAccessor, AspNetRequestAccessor>(Lifetime.Singleton);
|
||||
|
||||
composition.Register<IUmbracoApplicationLifetime, AspNetUmbracoApplicationLifetime>(Lifetime.Singleton);
|
||||
composition.Register<IPasswordHasher, AspNetPasswordHasher>();
|
||||
|
||||
|
||||
|
||||
composition.RegisterUnique<IMarchal, FrameworkMarchal>();
|
||||
composition.RegisterUnique<IProfilerHtml, WebProfiler>();
|
||||
|
||||
composition.ComposeWebMappingProfiles();
|
||||
|
||||
//register the install components
|
||||
//NOTE: i tried to not have these registered if we weren't installing or upgrading but post install when the site restarts
|
||||
//it still needs to use the install controller so we can't do that
|
||||
composition.ComposeInstaller();
|
||||
|
||||
// register membership stuff
|
||||
composition.Register(factory => MembershipProviderExtensions.GetMembersMembershipProvider());
|
||||
composition.Register(factory => Roles.Enabled ? Roles.Provider : new MembersRoleProvider(factory.GetInstance<IMemberService>()));
|
||||
@@ -71,11 +40,7 @@ namespace Umbraco.Web.Runtime
|
||||
composition.RegisterUnique<IMemberUserKeyProvider, MemberUserKeyProvider>();
|
||||
composition.RegisterUnique<IPublicAccessChecker, PublicAccessChecker>();
|
||||
|
||||
// register the umbraco context factory
|
||||
composition.RegisterUnique<IUmbracoContextFactory, UmbracoContextFactory>();
|
||||
|
||||
composition.RegisterUnique<ITemplateRenderer, TemplateRenderer>();
|
||||
composition.RegisterUnique<IMacroRenderer, MacroRenderer>();
|
||||
|
||||
composition.RegisterUnique<IUmbracoComponentRenderer, UmbracoComponentRenderer>();
|
||||
|
||||
@@ -98,16 +63,14 @@ namespace Umbraco.Web.Runtime
|
||||
composition.ConfigureForWeb();
|
||||
|
||||
composition
|
||||
// TODO: This will depend on if we use ServiceBasedControllerActivator - see notes in Startup.cs
|
||||
.ComposeUmbracoControllers(GetType().Assembly)
|
||||
.SetDefaultRenderMvcController<RenderMvcController>(); // default controller for template views
|
||||
|
||||
//we need to eagerly scan controller types since they will need to be routed
|
||||
composition.WithCollectionBuilder<SurfaceControllerTypeCollectionBuilder>()
|
||||
.Add(composition.TypeLoader.GetSurfaceControllers());
|
||||
var umbracoApiControllerTypes = composition.TypeLoader.GetUmbracoApiControllers().ToList();
|
||||
composition.WithCollectionBuilder<UmbracoApiControllerTypeCollectionBuilder>()
|
||||
.Add(umbracoApiControllerTypes);
|
||||
|
||||
|
||||
|
||||
// add all known factories, devs can then modify this list on application
|
||||
// startup either by binding to events or in their own global.asax
|
||||
@@ -120,6 +83,8 @@ namespace Umbraco.Web.Runtime
|
||||
// register preview SignalR hub
|
||||
composition.RegisterUnique(_ => GlobalHost.ConnectionManager.GetHubContext<PreviewHub>());
|
||||
|
||||
var umbracoApiControllerTypes = composition.TypeLoader.GetUmbracoApiControllers().ToList();
|
||||
|
||||
// register back office trees
|
||||
// the collection builder only accepts types inheriting from TreeControllerBase
|
||||
// and will filter out those that are not attributed with TreeAttribute
|
||||
@@ -127,18 +92,6 @@ namespace Umbraco.Web.Runtime
|
||||
.AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x)));
|
||||
|
||||
|
||||
|
||||
// STUFF that do not have to be moved to .NET CORE
|
||||
//----------------------------------------
|
||||
composition.RegisterUnique<ICookieManager, AspNetCookieManager>();
|
||||
composition.RegisterUnique<IApplicationShutdownRegistry, AspNetApplicationShutdownRegistry>();
|
||||
composition.RegisterUnique<IConfigManipulator, XmlConfigManipulator>();
|
||||
composition.RegisterUnique<IHttpContextAccessor, AspNetHttpContextAccessor>(); // required for hybrid accessors
|
||||
|
||||
composition.Register<AspNetSessionManager>(Lifetime.Singleton);
|
||||
composition.Register<ISessionIdResolver>(factory => factory.GetInstance<AspNetSessionManager>(), Lifetime.Singleton);
|
||||
composition.Register<ISessionManager>(factory => factory.GetInstance<AspNetSessionManager>(), Lifetime.Singleton);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
|
||||
namespace Umbraco.Web.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// When applied to an api controller it will be routed to the /Umbraco/BackOffice prefix route so we can determine if it
|
||||
/// is a back office route or not.
|
||||
/// </summary>
|
||||
// TODO: This has been moved to netcore so can be removed when ready
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
public sealed class IsBackOfficeAttribute : Attribute
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Umbraco.Web.WebApi
|
||||
{
|
||||
// TODO: This is moved to netcore so can be deleted when possible
|
||||
|
||||
public class UmbracoApiControllerTypeCollectionBuilder : TypeCollectionBuilderBase<UmbracoApiControllerTypeCollectionBuilder, UmbracoApiControllerTypeCollection, UmbracoApiController>
|
||||
{
|
||||
protected override UmbracoApiControllerTypeCollectionBuilder This => this;
|
||||
|
||||
Reference in New Issue
Block a user