Adds DatabaseServerRegistrar and ServerRegistrationEventHandler, we can now ensure that all server add themselves to the
database table automatically.
This commit is contained in:
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
public ServerRegistration BuildEntity(ServerRegistrationDto dto)
|
||||
{
|
||||
return new ServerRegistration(dto.Id, dto.ComputerName, dto.Address, dto.DateRegistered, dto.LastNotified);
|
||||
return new ServerRegistration(dto.Id, dto.Address, dto.ComputerName, dto.DateRegistered, dto.LastNotified);
|
||||
}
|
||||
|
||||
public ServerRegistrationDto BuildDto(ServerRegistration entity)
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Umbraco.Core.Services
|
||||
private Lazy<DataTypeService> _dataTypeService;
|
||||
private Lazy<FileService> _fileService;
|
||||
private Lazy<LocalizationService> _localizationService;
|
||||
private Lazy<ServerRegistrationService> _serverRegistrationService;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
@@ -47,6 +48,9 @@ namespace Umbraco.Core.Services
|
||||
var provider = dbUnitOfWorkProvider;
|
||||
var fileProvider = fileUnitOfWorkProvider;
|
||||
|
||||
if (_serverRegistrationService == null)
|
||||
_serverRegistrationService = new Lazy<ServerRegistrationService>(() => new ServerRegistrationService(provider, repositoryFactory.Value));
|
||||
|
||||
if (_userService == null)
|
||||
_userService = new Lazy<UserService>(() => new UserService(provider, repositoryFactory.Value));
|
||||
|
||||
@@ -72,6 +76,14 @@ namespace Umbraco.Core.Services
|
||||
_localizationService = new Lazy<LocalizationService>(() => new LocalizationService(provider, repositoryFactory.Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ServerRegistrationService"/>
|
||||
/// </summary>
|
||||
internal ServerRegistrationService ServerRegistrationService
|
||||
{
|
||||
get { return _serverRegistrationService.Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IContentService"/>
|
||||
/// </summary>
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
|
||||
23
src/Umbraco.Core/Sync/DatabaseServerRegistrar.cs
Normal file
23
src/Umbraco.Core/Sync/DatabaseServerRegistrar.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// A registrar that stores registered server nodes in a database
|
||||
/// </summary>
|
||||
internal class DatabaseServerRegistrar : IServerRegistrar
|
||||
{
|
||||
private readonly ServerRegistrationService _registrationService;
|
||||
|
||||
public DatabaseServerRegistrar(ServerRegistrationService registrationService)
|
||||
{
|
||||
_registrationService = registrationService;
|
||||
}
|
||||
|
||||
public IEnumerable<IServerAddress> Registrations
|
||||
{
|
||||
get { return _registrationService.GetActiveServers(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -676,6 +676,7 @@
|
||||
<Compile Include="Services\ServerRegistrationService.cs" />
|
||||
<Compile Include="Services\ServiceContext.cs" />
|
||||
<Compile Include="Services\UserService.cs" />
|
||||
<Compile Include="Sync\DatabaseServerRegistrar.cs" />
|
||||
<Compile Include="Sync\DefaultServerMessenger.cs" />
|
||||
<Compile Include="Sync\ICacheRefresher.cs" />
|
||||
<Compile Include="Sync\ServerSyncWebServiceClient.cs">
|
||||
|
||||
@@ -10,7 +10,7 @@ NOTES:
|
||||
* Compression/Combination/Minification is not enabled unless debug="false" is specified on the 'compiliation' element in the web.config
|
||||
* A new version will invalidate both client and server cache and create new persisted files
|
||||
-->
|
||||
<clientDependency version="3" fileDependencyExtensions=".js,.css">
|
||||
<clientDependency version="5" fileDependencyExtensions=".js,.css">
|
||||
|
||||
<fileRegistration defaultProvider="LoaderControlProvider">
|
||||
<providers>
|
||||
|
||||
14
src/Umbraco.Web/Routing/EnsureRoutableOutcome.cs
Normal file
14
src/Umbraco.Web/Routing/EnsureRoutableOutcome.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Reasons a request was not routable on the front-end
|
||||
/// </summary>
|
||||
internal enum EnsureRoutableOutcome
|
||||
{
|
||||
IsRoutable = 0,
|
||||
NotDocumentRequest = 10,
|
||||
NotReady = 11,
|
||||
NotConfigured = 12,
|
||||
NoContent = 13
|
||||
}
|
||||
}
|
||||
18
src/Umbraco.Web/Routing/RoutableAttemptEventArgs.cs
Normal file
18
src/Umbraco.Web/Routing/RoutableAttemptEventArgs.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Event args containing information about why the request was not routable, or if it is routable
|
||||
/// </summary>
|
||||
internal class RoutableAttemptEventArgs : UmbracoRequestEventArgs
|
||||
{
|
||||
public EnsureRoutableOutcome Outcome { get; private set; }
|
||||
|
||||
public RoutableAttemptEventArgs(EnsureRoutableOutcome reason, UmbracoContext umbracoContext, HttpContextBase httpContext)
|
||||
: base(umbracoContext, httpContext)
|
||||
{
|
||||
Outcome = reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/Umbraco.Web/Routing/UmbracoRequestEventArgs.cs
Normal file
20
src/Umbraco.Web/Routing/UmbracoRequestEventArgs.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Event args used for event launched during a request (like in the UmbracoModule)
|
||||
/// </summary>
|
||||
internal class UmbracoRequestEventArgs : EventArgs
|
||||
{
|
||||
public UmbracoContext UmbracoContext { get; private set; }
|
||||
public HttpContextBase HttpContext { get; private set; }
|
||||
|
||||
public UmbracoRequestEventArgs(UmbracoContext umbracoContext, HttpContextBase httpContext)
|
||||
{
|
||||
UmbracoContext = umbracoContext;
|
||||
HttpContext = httpContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
105
src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs
Normal file
105
src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Strategies
|
||||
{
|
||||
/// <summary>
|
||||
/// This will ensure that the server is automatically registered in the database as an active node
|
||||
/// on application startup and whenever a back office request occurs.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We do this on app startup to ensure that the server is in the database but we also do it for the first 'x' times
|
||||
/// a back office request is made so that we can tell if they are using https protocol which would update to that address
|
||||
/// in the database. The first front-end request probably wouldn't be an https request.
|
||||
///
|
||||
/// For back office requests (so that we don't constantly make db calls), we'll only update the database when we detect at least
|
||||
/// a timespan of 1 minute between requests.
|
||||
/// </remarks>
|
||||
public sealed class ServerRegistrationEventHandler : ApplicationEventHandler
|
||||
{
|
||||
private static bool _initUpdated = false;
|
||||
private static DateTime _lastUpdated = DateTime.MinValue;
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Update the database with this entry and bind to request events
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
//bind to event
|
||||
UmbracoModule.RouteAttempt += UmbracoModuleRouteAttempt;
|
||||
}
|
||||
|
||||
|
||||
static void UmbracoModuleRouteAttempt(object sender, Routing.RoutableAttemptEventArgs e)
|
||||
{
|
||||
if (e.HttpContext.Request == null || e.HttpContext.Request.Url == null) return;
|
||||
|
||||
if (e.Outcome == EnsureRoutableOutcome.IsRoutable)
|
||||
{
|
||||
using (var lck = new UpgradeableReadLock(Locker))
|
||||
{
|
||||
//we only want to do the initial update once
|
||||
if (!_initUpdated)
|
||||
{
|
||||
lck.UpgradeToWriteLock();
|
||||
_initUpdated = true;
|
||||
UpdateServerEntry(e.HttpContext, e.UmbracoContext.Application);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if it is not a document request, we'll check if it is a back end request
|
||||
if (e.Outcome == EnsureRoutableOutcome.NotDocumentRequest)
|
||||
{
|
||||
var authority = e.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority);
|
||||
var afterAuthority = e.HttpContext.Request.Url.GetLeftPart(UriPartial.Query)
|
||||
.TrimStart(authority)
|
||||
.TrimStart("/");
|
||||
|
||||
//check if this is in the umbraco back office
|
||||
if (afterAuthority.InvariantStartsWith(GlobalSettings.Path.TrimStart("/")))
|
||||
{
|
||||
//yup it's a back office request!
|
||||
using (var lck = new UpgradeableReadLock(Locker))
|
||||
{
|
||||
//we don't want to update if it's not been at least a minute since last time
|
||||
var isItAMinute = DateTime.Now.Subtract(_lastUpdated).TotalSeconds >= 60;
|
||||
if (isItAMinute)
|
||||
{
|
||||
lck.UpgradeToWriteLock();
|
||||
_initUpdated = true;
|
||||
_lastUpdated = DateTime.Now;
|
||||
UpdateServerEntry(e.HttpContext, e.UmbracoContext.Application);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void UpdateServerEntry(HttpContextBase httpContext, ApplicationContext applicationContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
var address = httpContext.Request.Url.GetLeftPart(UriPartial.Authority);
|
||||
applicationContext.Services.ServerRegistrationService.EnsureActive(address);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<ServerRegistrationEventHandler>("Failed to update server record in database.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -351,7 +351,9 @@
|
||||
<Compile Include="Routing\ContentFinderByPageIdQuery.cs" />
|
||||
<Compile Include="Mvc\SurfaceControllerResolver.cs" />
|
||||
<Compile Include="Routing\ContentFinderByNotFoundHandlers.cs" />
|
||||
<Compile Include="Routing\RoutableAttemptEventArgs.cs" />
|
||||
<Compile Include="Routing\NotFoundHandlerHelper.cs" />
|
||||
<Compile Include="Routing\EnsureRoutableOutcome.cs" />
|
||||
<Compile Include="Routing\PublishedContentRequestEngine.cs" />
|
||||
<Compile Include="Search\ExamineEvents.cs" />
|
||||
<Compile Include="Security\WebSecurity.cs" />
|
||||
@@ -360,6 +362,7 @@
|
||||
<Compile Include="Strategies\Publishing\UpdateCacheAfterPublish.cs" />
|
||||
<Compile Include="Strategies\Publishing\UpdateCacheAfterUnPublish.cs" />
|
||||
<Compile Include="Strategies\Migrations\EnsureAppsTreesUpdatedOnUpgrade.cs" />
|
||||
<Compile Include="Strategies\ServerRegistrationEventHandler.cs" />
|
||||
<Compile Include="Templates\TemplateRenderer.cs" />
|
||||
<Compile Include="Templates\TemplateUtilities.cs" />
|
||||
<Compile Include="Trees\PartialViewMacrosTree.cs" />
|
||||
@@ -506,6 +509,7 @@
|
||||
<Compile Include="umbraco.presentation\umbraco\nodeFactory\Node.cs" />
|
||||
<Compile Include="umbraco.presentation\umbraco\nodeFactory\Nodes.cs" />
|
||||
<Compile Include="umbraco.presentation\umbraco\nodeFactory\Property.cs" />
|
||||
<Compile Include="Routing\UmbracoRequestEventArgs.cs" />
|
||||
<Compile Include="UmbracoUserControl.cs">
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
|
||||
@@ -94,8 +94,14 @@ namespace Umbraco.Web
|
||||
}
|
||||
|
||||
// do not process if this request is not a front-end routable page
|
||||
if (!EnsureUmbracoRoutablePage(umbracoContext, httpContext))
|
||||
return;
|
||||
var isRoutableAttempt = EnsureUmbracoRoutablePage(umbracoContext, httpContext);
|
||||
//raise event here
|
||||
OnRouteAttempt(new RoutableAttemptEventArgs(isRoutableAttempt.Result, umbracoContext, httpContext));
|
||||
if (!isRoutableAttempt.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
httpContext.Trace.Write("UmbracoModule", "Umbraco request confirmed");
|
||||
|
||||
@@ -148,7 +154,7 @@ namespace Umbraco.Web
|
||||
#region Route helper methods
|
||||
|
||||
/// <summary>
|
||||
/// This is a performance tweak to check if this is a .css, .js or .ico file request since
|
||||
/// This is a performance tweak to check if this is a .css, .js or .ico, .jpg, .jpeg, .png, .gif file request since
|
||||
/// .Net will pass these requests through to the module when in integrated mode.
|
||||
/// We want to ignore all of these requests immediately.
|
||||
/// </summary>
|
||||
@@ -156,7 +162,7 @@ namespace Umbraco.Web
|
||||
/// <returns></returns>
|
||||
internal bool IsClientSideRequest(Uri url)
|
||||
{
|
||||
var toIgnore = new[] { ".js", ".css", ".ico" };
|
||||
var toIgnore = new[] { ".js", ".css", ".ico", ".png", ".jpg", ".jpeg", ".gif" };
|
||||
return toIgnore.Any(x => Path.GetExtension(url.LocalPath).InvariantEquals(x));
|
||||
}
|
||||
|
||||
@@ -166,24 +172,34 @@ namespace Umbraco.Web
|
||||
/// <param name="context"></param>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <returns></returns>
|
||||
internal bool EnsureUmbracoRoutablePage(UmbracoContext context, HttpContextBase httpContext)
|
||||
internal Attempt<EnsureRoutableOutcome> EnsureUmbracoRoutablePage(UmbracoContext context, HttpContextBase httpContext)
|
||||
{
|
||||
var uri = context.OriginalRequestUrl;
|
||||
|
||||
var reason = EnsureRoutableOutcome.IsRoutable;;
|
||||
|
||||
// ensure this is a document request
|
||||
if (!EnsureDocumentRequest(httpContext, uri))
|
||||
return false;
|
||||
{
|
||||
reason = EnsureRoutableOutcome.NotDocumentRequest;
|
||||
}
|
||||
// ensure Umbraco is ready to serve documents
|
||||
if (!EnsureIsReady(httpContext, uri))
|
||||
return false;
|
||||
else if (!EnsureIsReady(httpContext, uri))
|
||||
{
|
||||
reason = EnsureRoutableOutcome.NotReady;
|
||||
}
|
||||
// ensure Umbraco is properly configured to serve documents
|
||||
if (!EnsureIsConfigured(httpContext, uri))
|
||||
return false;
|
||||
else if (!EnsureIsConfigured(httpContext, uri))
|
||||
{
|
||||
reason = EnsureRoutableOutcome.NotConfigured;
|
||||
}
|
||||
// ensure Umbraco has documents to serve
|
||||
if (!EnsureHasContent(context, httpContext))
|
||||
return false;
|
||||
else if (!EnsureHasContent(context, httpContext))
|
||||
{
|
||||
reason = EnsureRoutableOutcome.NoContent;
|
||||
}
|
||||
|
||||
return true;
|
||||
return new Attempt<EnsureRoutableOutcome>(reason == EnsureRoutableOutcome.IsRoutable, reason);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -318,8 +334,7 @@ namespace Umbraco.Web
|
||||
/// Rewrites to the correct Umbraco handler, either WebForms or Mvc
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="currentQuery"></param>
|
||||
/// <param name="engine"> </param>
|
||||
/// <param name="pcr"> </param>
|
||||
private void RewriteToUmbracoHandler(HttpContextBase context, PublishedContentRequest pcr)
|
||||
{
|
||||
// NOTE: we do not want to use TransferRequest even though many docs say it is better with IIS7, turns out this is
|
||||
@@ -432,5 +447,14 @@ namespace Umbraco.Web
|
||||
i.DisposeIfDisposable();
|
||||
}
|
||||
}
|
||||
|
||||
#region Events
|
||||
internal static event EventHandler<RoutableAttemptEventArgs> RouteAttempt;
|
||||
private void OnRouteAttempt(RoutableAttemptEventArgs args)
|
||||
{
|
||||
if (RouteAttempt != null)
|
||||
RouteAttempt(this, args);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user