2016-09-01 11:25:00 +02:00
|
|
|
|
using System;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Collections.Specialized;
|
|
|
|
|
|
using System.Configuration;
|
|
|
|
|
|
using System.Linq;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using System.Web;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
using System.Web.Configuration;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using System.Web.Http;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
using System.Web.Http.Dispatcher;
|
|
|
|
|
|
using System.Web.Mvc;
|
|
|
|
|
|
using System.Web.Routing;
|
|
|
|
|
|
using ClientDependency.Core.Config;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using LightInject;
|
2016-10-19 11:16:33 +02:00
|
|
|
|
using Microsoft.AspNet.SignalR;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using Umbraco.Core;
|
|
|
|
|
|
using Umbraco.Core.Components;
|
|
|
|
|
|
using Umbraco.Core.Configuration;
|
2017-05-30 15:46:25 +02:00
|
|
|
|
using Umbraco.Core.Composing;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using Umbraco.Core.Dictionary;
|
|
|
|
|
|
using Umbraco.Core.Events;
|
|
|
|
|
|
using Umbraco.Core.Logging;
|
|
|
|
|
|
using Umbraco.Core.Macros;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
using Umbraco.Core.Profiling;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using Umbraco.Core.PropertyEditors;
|
|
|
|
|
|
using Umbraco.Core.PropertyEditors.ValueConverters;
|
|
|
|
|
|
using Umbraco.Core.Services;
|
2017-07-11 19:13:45 +02:00
|
|
|
|
using Umbraco.Web.Cache;
|
2016-11-05 19:23:55 +01:00
|
|
|
|
using Umbraco.Web.DI;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using Umbraco.Web.Dictionary;
|
|
|
|
|
|
using Umbraco.Web.Editors;
|
|
|
|
|
|
using Umbraco.Web.HealthCheck;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
using Umbraco.Web.Install;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using Umbraco.Web.Media;
|
|
|
|
|
|
using Umbraco.Web.Media.ThumbnailProviders;
|
|
|
|
|
|
using Umbraco.Web.Mvc;
|
|
|
|
|
|
using Umbraco.Web.PublishedCache;
|
|
|
|
|
|
using Umbraco.Web.Routing;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
using Umbraco.Web.Security;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using Umbraco.Web.Services;
|
2016-10-19 11:16:33 +02:00
|
|
|
|
using Umbraco.Web.SignalR;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
using Umbraco.Web.UI.JavaScript;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
using Umbraco.Web.WebApi;
|
|
|
|
|
|
using Umbraco.Web._Legacy.Actions;
|
2017-07-27 12:01:38 +02:00
|
|
|
|
using Umbraco.Examine;
|
2017-05-30 18:13:11 +02:00
|
|
|
|
using Current = Umbraco.Web.Composing.Current;
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Web
|
|
|
|
|
|
{
|
|
|
|
|
|
[RequireComponent(typeof(CoreRuntimeComponent))]
|
|
|
|
|
|
public class WebRuntimeComponent : UmbracoComponentBase, IRuntimeComponent
|
|
|
|
|
|
{
|
2016-10-07 14:34:55 +02:00
|
|
|
|
public override void Compose(Composition composition)
|
2016-09-01 11:25:00 +02:00
|
|
|
|
{
|
2016-10-07 14:34:55 +02:00
|
|
|
|
base.Compose(composition);
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2017-07-19 13:42:47 +02:00
|
|
|
|
composition.Container.RegisterFrom<WebMappingProfilesCompositionRoot>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2017-05-30 15:33:13 +02:00
|
|
|
|
var pluginManager = composition.Container.GetInstance<TypeLoader>();
|
2016-10-07 14:34:55 +02:00
|
|
|
|
var logger = composition.Container.GetInstance<ILogger>();
|
|
|
|
|
|
var proflog = composition.Container.GetInstance<ProfilingLogger>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
|
|
|
|
|
// register the http context and umbraco context accessors
|
|
|
|
|
|
// we *should* use the HttpContextUmbracoContextAccessor, however there are cases when
|
|
|
|
|
|
// we have no http context, eg when booting Umbraco or in background threads, so instead
|
|
|
|
|
|
// let's use an hybrid accessor that can fall back to a ThreadStatic context.
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterSingleton<IUmbracoContextAccessor, HybridUmbracoContextAccessor>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2016-09-01 19:06:08 +02:00
|
|
|
|
// register the 'current' umbraco context - transient - for eg controllers
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.Register(factory => factory.GetInstance<IUmbracoContextAccessor>().UmbracoContext);
|
2016-09-01 19:06:08 +02:00
|
|
|
|
|
2016-09-01 11:25:00 +02:00
|
|
|
|
// register a per-request HttpContextBase object
|
|
|
|
|
|
// is per-request so only one wrapper is created per request
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.Register<HttpContextBase>(factory => new HttpContextWrapper(factory.GetInstance<IHttpContextAccessor>().HttpContext), new PerRequestLifeTime());
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
|
|
|
|
|
// register the facade accessor - the "current" facade is in the umbraco context
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterSingleton<IFacadeAccessor, UmbracoContextFacadeAccessor>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
|
|
|
|
|
// register a per-request UmbracoContext object
|
|
|
|
|
|
// no real need to be per request but assuming it is faster
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.Register(factory => factory.GetInstance<IUmbracoContextAccessor>().UmbracoContext, new PerRequestLifeTime());
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
|
|
|
|
|
// register the umbraco helper
|
2016-09-01 19:06:08 +02:00
|
|
|
|
// fixme - FUCK! how can this even work, it's not a singleton!
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterSingleton<UmbracoHelper>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2017-07-11 19:13:45 +02:00
|
|
|
|
// register distributed cache
|
|
|
|
|
|
composition.Container.RegisterSingleton(f => new DistributedCache());
|
|
|
|
|
|
|
2016-09-01 11:25:00 +02:00
|
|
|
|
// replace some services
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterSingleton<IEventMessagesFactory, DefaultEventMessagesFactory>();
|
|
|
|
|
|
composition.Container.RegisterSingleton<IEventMessagesAccessor, HybridEventMessagesAccessor>();
|
|
|
|
|
|
composition.Container.RegisterSingleton<IApplicationTreeService, ApplicationTreeService>();
|
|
|
|
|
|
composition.Container.RegisterSingleton<ISectionService, SectionService>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterSingleton<IExamineIndexCollectionAccessor, ExamineIndexCollectionAccessor>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
|
|
|
|
|
// IoC setup for LightInject for MVC/WebApi
|
2017-05-12 14:49:44 +02:00
|
|
|
|
// see comments on MixedLightInjectScopeManagerProvider for explainations of what we are doing here
|
|
|
|
|
|
var smp = composition.Container.ScopeManagerProvider as MixedLightInjectScopeManagerProvider;
|
|
|
|
|
|
if (smp == null) throw new Exception("Container.ScopeManagerProvider is not MixedLightInjectScopeManagerProvider.");
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.EnableMvc(); // does container.EnablePerWebRequestScope()
|
|
|
|
|
|
composition.Container.ScopeManagerProvider = smp; // reverts - we will do it last (in WebRuntime)
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterMvcControllers(pluginManager, GetType().Assembly);
|
|
|
|
|
|
composition.Container.EnableWebApi(GlobalConfiguration.Configuration);
|
|
|
|
|
|
composition.Container.RegisterApiControllers(pluginManager, GetType().Assembly);
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
XsltExtensionCollectionBuilder.Register(composition.Container)
|
2016-09-01 11:25:00 +02:00
|
|
|
|
.AddExtensionObjectProducer(() => pluginManager.ResolveXsltExtensions());
|
|
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterCollectionBuilder<EditorValidatorCollectionBuilder>()
|
2017-05-30 15:33:13 +02:00
|
|
|
|
.Add(() => pluginManager.GetTypes<IEditorValidator>());
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
|
|
|
|
|
// set the default RenderMvcController
|
|
|
|
|
|
Current.DefaultRenderMvcControllerType = typeof(RenderMvcController); // fixme WRONG!
|
|
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
ActionCollectionBuilder.Register(composition.Container)
|
2016-09-01 11:25:00 +02:00
|
|
|
|
.SetProducer(() => pluginManager.ResolveActions());
|
|
|
|
|
|
|
|
|
|
|
|
var surfaceControllerTypes = new SurfaceControllerTypeCollection(pluginManager.ResolveSurfaceControllers());
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterInstance(surfaceControllerTypes);
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
|
|
|
|
|
var umbracoApiControllerTypes = new UmbracoApiControllerTypeCollection(pluginManager.ResolveUmbracoApiControllers());
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterInstance(umbracoApiControllerTypes);
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
|
|
|
|
|
// both TinyMceValueConverter (in Core) and RteMacroRenderingValueConverter (in Web) will be
|
|
|
|
|
|
// discovered when CoreBootManager configures the converters. We HAVE to remove one of them
|
|
|
|
|
|
// here because there cannot be two converters for one property editor - and we want the full
|
|
|
|
|
|
// RteMacroRenderingValueConverter that converts macros, etc. So remove TinyMceValueConverter.
|
|
|
|
|
|
// (the limited one, defined in Core, is there for tests) - same for others
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.GetInstance<PropertyValueConverterCollectionBuilder>()
|
2016-09-01 11:25:00 +02:00
|
|
|
|
.Remove<TinyMceValueConverter>()
|
|
|
|
|
|
.Remove<TextStringValueConverter>()
|
|
|
|
|
|
.Remove<MarkdownEditorValueConverter>()
|
|
|
|
|
|
.Remove<ImageCropperValueConverter>();
|
|
|
|
|
|
|
|
|
|
|
|
// add all known factories, devs can then modify this list on application
|
|
|
|
|
|
// startup either by binding to events or in their own global.asax
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterCollectionBuilder<FilteredControllerFactoryCollectionBuilder>()
|
2016-09-01 11:25:00 +02:00
|
|
|
|
.Append<RenderControllerFactory>();
|
|
|
|
|
|
|
2016-10-13 21:08:07 +02:00
|
|
|
|
composition.Container.RegisterCollectionBuilder<UrlProviderCollectionBuilder>()
|
2016-09-01 11:25:00 +02:00
|
|
|
|
//.Append<AliasUrlProvider>() // not enabled by default
|
|
|
|
|
|
.Append<DefaultUrlProvider>()
|
|
|
|
|
|
.Append<CustomRouteUrlProvider>();
|
|
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterSingleton<IContentLastChanceFinder, ContentFinderByLegacy404>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2016-10-13 21:08:07 +02:00
|
|
|
|
composition.Container.RegisterCollectionBuilder<ContentFinderCollectionBuilder>()
|
2016-09-01 11:25:00 +02:00
|
|
|
|
// all built-in finders in the correct order,
|
|
|
|
|
|
// devs can then modify this list on application startup
|
|
|
|
|
|
.Append<ContentFinderByPageIdQuery>()
|
|
|
|
|
|
.Append<ContentFinderByNiceUrl>()
|
|
|
|
|
|
.Append<ContentFinderByIdPath>()
|
|
|
|
|
|
.Append<ContentFinderByNiceUrlAndTemplate>()
|
|
|
|
|
|
.Append<ContentFinderByProfile>()
|
|
|
|
|
|
.Append<ContentFinderByUrlAlias>()
|
|
|
|
|
|
.Append<ContentFinderByRedirectUrl>();
|
|
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterSingleton<ISiteDomainHelper, SiteDomainHelper>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterCollectionBuilder<ThumbnailProviderCollectionBuilder>()
|
2016-09-01 11:25:00 +02:00
|
|
|
|
.Add(pluginManager.ResolveThumbnailProviders());
|
|
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterCollectionBuilder<ImageUrlProviderCollectionBuilder>()
|
2016-09-01 11:25:00 +02:00
|
|
|
|
.Append(pluginManager.ResolveImageUrlProviders());
|
|
|
|
|
|
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterSingleton<ICultureDictionaryFactory, DefaultCultureDictionaryFactory>();
|
2016-09-01 11:25:00 +02:00
|
|
|
|
|
2016-09-08 18:43:58 +02:00
|
|
|
|
// register *all* checks, except those marked [HideFromTypeFinder] of course
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterCollectionBuilder<HealthCheckCollectionBuilder>()
|
2017-05-30 15:33:13 +02:00
|
|
|
|
.Add(() => pluginManager.GetTypes<HealthCheck.HealthCheck>());
|
2016-09-01 19:06:08 +02:00
|
|
|
|
|
2016-09-08 18:43:58 +02:00
|
|
|
|
// auto-register views
|
2016-10-07 14:34:55 +02:00
|
|
|
|
composition.Container.RegisterAuto(typeof(UmbracoViewPage<>));
|
2016-10-13 21:08:07 +02:00
|
|
|
|
|
|
|
|
|
|
// register facade router
|
|
|
|
|
|
composition.Container.Register<FacadeRouter>();
|
|
|
|
|
|
composition.Container.Register(_ => UmbracoConfig.For.UmbracoSettings().WebRouting);
|
2016-10-19 11:16:33 +02:00
|
|
|
|
|
|
|
|
|
|
// register preview SignalR hub
|
|
|
|
|
|
composition.Container.Register(_ => GlobalHost.ConnectionManager.GetHubContext<PreviewHub>(), new PerContainerLifetime());
|
2016-09-01 11:25:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-01 19:06:08 +02:00
|
|
|
|
internal void Initialize(
|
|
|
|
|
|
IRuntimeState runtime,
|
2016-10-11 18:52:01 +02:00
|
|
|
|
IUmbracoContextAccessor umbracoContextAccessor,
|
2016-09-01 19:06:08 +02:00
|
|
|
|
SurfaceControllerTypeCollection surfaceControllerTypes,
|
2016-10-18 17:09:26 +02:00
|
|
|
|
UmbracoApiControllerTypeCollection apiControllerTypes,
|
|
|
|
|
|
IFacadeService facadeService,
|
|
|
|
|
|
IUserService userService,
|
|
|
|
|
|
UrlProviderCollection urlProviders)
|
2016-09-01 11:25:00 +02:00
|
|
|
|
{
|
2016-09-01 19:06:08 +02:00
|
|
|
|
// setup mvc and webapi services
|
|
|
|
|
|
SetupMvcAndWebApi();
|
|
|
|
|
|
|
|
|
|
|
|
// Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK]
|
|
|
|
|
|
ClientDependency.Core.CompositeFiles.Providers.XmlFileMapper.FileMapVirtualFolder = "~/App_Data/TEMP/ClientDependency";
|
|
|
|
|
|
ClientDependency.Core.CompositeFiles.Providers.BaseCompositeFileProcessingProvider.UrlTypeDefault = ClientDependency.Core.CompositeFiles.Providers.CompositeUrlType.Base64QueryStrings;
|
|
|
|
|
|
|
|
|
|
|
|
var section = ConfigurationManager.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
|
|
|
|
|
|
if (section != null)
|
2016-09-01 11:25:00 +02:00
|
|
|
|
{
|
2016-09-01 19:06:08 +02:00
|
|
|
|
//set the max url length for CDF to be the smallest of the max query length, max request length
|
|
|
|
|
|
ClientDependency.Core.CompositeFiles.CompositeDependencyHandler.MaxHandlerUrlLength = Math.Min(section.MaxQueryStringLength, section.MaxRequestLength);
|
2016-09-01 11:25:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-09-01 19:06:08 +02:00
|
|
|
|
//Register a custom renderer - used to process property editor dependencies
|
|
|
|
|
|
var renderer = new DependencyPathRenderer();
|
|
|
|
|
|
renderer.Initialize("Umbraco.DependencyPathRenderer", new NameValueCollection
|
2016-09-01 11:25:00 +02:00
|
|
|
|
{
|
2016-09-01 19:06:08 +02:00
|
|
|
|
{ "compositeFileHandlerPath", ClientDependencySettings.Instance.CompositeFileHandlerPath }
|
|
|
|
|
|
});
|
|
|
|
|
|
ClientDependencySettings.Instance.MvcRendererCollection.Add(renderer);
|
|
|
|
|
|
|
|
|
|
|
|
// Disable the X-AspNetMvc-Version HTTP Header
|
|
|
|
|
|
MvcHandler.DisableMvcResponseHeader = true;
|
|
|
|
|
|
|
|
|
|
|
|
InstallHelper.DeleteLegacyInstaller();
|
|
|
|
|
|
|
|
|
|
|
|
// wrap view engines in the profiling engine
|
|
|
|
|
|
WrapViewEngines(ViewEngines.Engines);
|
|
|
|
|
|
|
|
|
|
|
|
// add global filters
|
|
|
|
|
|
ConfigureGlobalFilters();
|
|
|
|
|
|
|
|
|
|
|
|
// set routes
|
2016-10-11 18:52:01 +02:00
|
|
|
|
CreateRoutes(umbracoContextAccessor, surfaceControllerTypes, apiControllerTypes);
|
2016-09-01 19:06:08 +02:00
|
|
|
|
|
2016-09-11 19:57:33 +02:00
|
|
|
|
// get an http context
|
2016-10-18 17:09:26 +02:00
|
|
|
|
// at that moment, HttpContext.Current != null but its .Request property is null
|
2016-09-11 19:57:33 +02:00
|
|
|
|
var httpContext = new HttpContextWrapper(HttpContext.Current);
|
|
|
|
|
|
|
2016-10-18 17:09:26 +02:00
|
|
|
|
// ensure there is an UmbracoContext
|
|
|
|
|
|
// (also sets the accessor)
|
|
|
|
|
|
// this is a *temp* UmbracoContext
|
|
|
|
|
|
UmbracoContext.EnsureContext(
|
|
|
|
|
|
umbracoContextAccessor,
|
|
|
|
|
|
new HttpContextWrapper(HttpContext.Current),
|
|
|
|
|
|
facadeService,
|
|
|
|
|
|
new WebSecurity(httpContext, userService),
|
2016-09-01 19:06:08 +02:00
|
|
|
|
UmbracoConfig.For.UmbracoSettings(),
|
2016-10-18 17:09:26 +02:00
|
|
|
|
urlProviders);
|
2016-09-01 19:06:08 +02:00
|
|
|
|
|
|
|
|
|
|
// ensure WebAPI is initialized, after everything
|
|
|
|
|
|
GlobalConfiguration.Configuration.EnsureInitialized();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void ConfigureGlobalFilters()
|
|
|
|
|
|
{
|
|
|
|
|
|
GlobalFilters.Filters.Add(new EnsurePartialViewMacroViewContextFilterAttribute());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// internal for tests
|
|
|
|
|
|
internal static void WrapViewEngines(IList<IViewEngine> viewEngines)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (viewEngines == null || viewEngines.Count == 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
var originalEngines = viewEngines.Select(e => e).ToArray();
|
|
|
|
|
|
viewEngines.Clear();
|
|
|
|
|
|
foreach (var engine in originalEngines)
|
|
|
|
|
|
{
|
|
|
|
|
|
var wrappedEngine = engine is ProfilingViewEngine ? engine : new ProfilingViewEngine(engine);
|
|
|
|
|
|
viewEngines.Add(wrappedEngine);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// internal for tests
|
|
|
|
|
|
internal static void CreateRoutes(
|
2016-10-11 18:52:01 +02:00
|
|
|
|
IUmbracoContextAccessor umbracoContextAccessor,
|
2016-09-01 19:06:08 +02:00
|
|
|
|
SurfaceControllerTypeCollection surfaceControllerTypes,
|
|
|
|
|
|
UmbracoApiControllerTypeCollection apiControllerTypes)
|
|
|
|
|
|
{
|
|
|
|
|
|
var umbracoPath = GlobalSettings.UmbracoMvcArea;
|
|
|
|
|
|
|
|
|
|
|
|
// create the front-end route
|
|
|
|
|
|
var defaultRoute = RouteTable.Routes.MapRoute(
|
|
|
|
|
|
"Umbraco_default",
|
|
|
|
|
|
umbracoPath + "/RenderMvc/{action}/{id}",
|
|
|
|
|
|
new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional }
|
|
|
|
|
|
);
|
2016-10-11 18:52:01 +02:00
|
|
|
|
defaultRoute.RouteHandler = new RenderRouteHandler(umbracoContextAccessor, ControllerBuilder.Current.GetControllerFactory());
|
2016-09-01 19:06:08 +02:00
|
|
|
|
|
|
|
|
|
|
// register install routes
|
|
|
|
|
|
RouteTable.Routes.RegisterArea<UmbracoInstallArea>();
|
|
|
|
|
|
|
|
|
|
|
|
// register all back office routes
|
|
|
|
|
|
RouteTable.Routes.RegisterArea<BackOfficeArea>();
|
|
|
|
|
|
|
|
|
|
|
|
// plugin controllers must come first because the next route will catch many things
|
|
|
|
|
|
RoutePluginControllers(surfaceControllerTypes, apiControllerTypes);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void RoutePluginControllers(
|
|
|
|
|
|
SurfaceControllerTypeCollection surfaceControllerTypes,
|
|
|
|
|
|
UmbracoApiControllerTypeCollection apiControllerTypes)
|
|
|
|
|
|
{
|
|
|
|
|
|
var umbracoPath = GlobalSettings.UmbracoMvcArea;
|
|
|
|
|
|
|
|
|
|
|
|
// need to find the plugin controllers and route them
|
|
|
|
|
|
var pluginControllers = surfaceControllerTypes.Concat(apiControllerTypes).ToArray();
|
|
|
|
|
|
|
|
|
|
|
|
// local controllers do not contain the attribute
|
|
|
|
|
|
var localControllers = pluginControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace());
|
|
|
|
|
|
foreach (var s in localControllers)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (TypeHelper.IsTypeAssignableFrom<SurfaceController>(s))
|
|
|
|
|
|
RouteLocalSurfaceController(s, umbracoPath);
|
|
|
|
|
|
else if (TypeHelper.IsTypeAssignableFrom<UmbracoApiController>(s))
|
|
|
|
|
|
RouteLocalApiController(s, umbracoPath);
|
2016-09-01 11:25:00 +02:00
|
|
|
|
}
|
2016-09-01 19:06:08 +02:00
|
|
|
|
|
|
|
|
|
|
// get the plugin controllers that are unique to each area (group by)
|
|
|
|
|
|
var pluginSurfaceControlleres = pluginControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace() == false);
|
|
|
|
|
|
var groupedAreas = pluginSurfaceControlleres.GroupBy(controller => PluginController.GetMetadata(controller).AreaName);
|
|
|
|
|
|
// loop through each area defined amongst the controllers
|
|
|
|
|
|
foreach (var g in groupedAreas)
|
|
|
|
|
|
{
|
|
|
|
|
|
// create & register an area for the controllers (this will throw an exception if all controllers are not in the same area)
|
|
|
|
|
|
var pluginControllerArea = new PluginControllerArea(g.Select(PluginController.GetMetadata));
|
|
|
|
|
|
RouteTable.Routes.RegisterArea(pluginControllerArea);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void RouteLocalApiController(Type controller, string umbracoPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
var meta = PluginController.GetMetadata(controller);
|
|
|
|
|
|
var url = umbracoPath + (meta.IsBackOffice ? "/BackOffice" : "") + "/Api/" + meta.ControllerName + "/{action}/{id}";
|
|
|
|
|
|
var route = RouteTable.Routes.MapHttpRoute(
|
|
|
|
|
|
$"umbraco-api-{meta.ControllerName}",
|
|
|
|
|
|
url, // url to match
|
|
|
|
|
|
new { controller = meta.ControllerName, id = UrlParameter.Optional },
|
|
|
|
|
|
new[] { meta.ControllerNamespace });
|
|
|
|
|
|
if (route.DataTokens == null) // web api routes don't set the data tokens object
|
|
|
|
|
|
route.DataTokens = new RouteValueDictionary();
|
|
|
|
|
|
route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "api"); //ensure the umbraco token is set
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void RouteLocalSurfaceController(Type controller, string umbracoPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
var meta = PluginController.GetMetadata(controller);
|
|
|
|
|
|
var url = umbracoPath + "/Surface/" + meta.ControllerName + "/{action}/{id}";
|
|
|
|
|
|
var route = RouteTable.Routes.MapRoute(
|
|
|
|
|
|
$"umbraco-surface-{meta.ControllerName}",
|
|
|
|
|
|
url, // url to match
|
|
|
|
|
|
new { controller = meta.ControllerName, action = "Index", id = UrlParameter.Optional },
|
|
|
|
|
|
new[] { meta.ControllerNamespace }); // look in this namespace to create the controller
|
|
|
|
|
|
route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "surface"); // ensure the umbraco token is set
|
|
|
|
|
|
route.DataTokens.Add("UseNamespaceFallback", false); // don't look anywhere else except this namespace!
|
|
|
|
|
|
// make it use our custom/special SurfaceMvcHandler
|
|
|
|
|
|
route.RouteHandler = new SurfaceRouteHandler();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void SetupMvcAndWebApi()
|
|
|
|
|
|
{
|
|
|
|
|
|
//don't output the MVC version header (security)
|
|
|
|
|
|
MvcHandler.DisableMvcResponseHeader = true;
|
|
|
|
|
|
|
|
|
|
|
|
// set master controller factory
|
|
|
|
|
|
var controllerFactory = new MasterControllerFactory(() => Current.FilteredControllerFactories);
|
|
|
|
|
|
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
|
|
|
|
|
|
|
|
|
|
|
|
// set the render & plugin view engines
|
|
|
|
|
|
ViewEngines.Engines.Add(new RenderViewEngine());
|
|
|
|
|
|
ViewEngines.Engines.Add(new PluginViewEngine());
|
|
|
|
|
|
|
|
|
|
|
|
//set model binder
|
|
|
|
|
|
ModelBinderProviders.BinderProviders.Add(new ContentModelBinder()); // is a provider
|
|
|
|
|
|
|
|
|
|
|
|
////add the profiling action filter
|
|
|
|
|
|
//GlobalFilters.Filters.Add(new ProfilingActionFilter());
|
|
|
|
|
|
|
|
|
|
|
|
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector),
|
|
|
|
|
|
new NamespaceHttpControllerSelector(GlobalConfiguration.Configuration));
|
2016-09-01 11:25:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|