Merge
This commit is contained in:
@@ -14,6 +14,7 @@ using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Publishing;
|
||||
using Umbraco.Core.Macros;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Sync;
|
||||
using MigrationsVersionFourNineZero = Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -165,6 +166,16 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
protected virtual void InitializeResolvers()
|
||||
{
|
||||
//by default we'll use the standard configuration based sync
|
||||
ServerRegistrarResolver.Current = new ServerRegistrarResolver(
|
||||
new ConfigServerRegistrar());
|
||||
|
||||
//by default (outside of the web) we'll use the default server messenger without
|
||||
//supplying a username/password, this will automatically disable distributed calls
|
||||
// .. we'll override this in the WebBootManager
|
||||
ServerMessengerResolver.Current = new ServerMessengerResolver(
|
||||
new DefaultServerMessenger());
|
||||
|
||||
RepositoryResolver.Current = new RepositoryResolver(
|
||||
new RepositoryFactory());
|
||||
|
||||
|
||||
@@ -9,25 +9,6 @@ namespace Umbraco.Core.Publishing
|
||||
public abstract class BasePublishingStrategy : IPublishingStrategy
|
||||
{
|
||||
|
||||
internal abstract Attempt<PublishStatus> PublishInternal(IContent content, int userId);
|
||||
|
||||
/// <summary>
|
||||
/// Publishes a list of content items
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="includeUnpublishedDocuments">
|
||||
/// By default this is set to true which means that it will publish any content item in the list that is completely unpublished and
|
||||
/// not visible on the front-end. If set to false, this will only publish content that is live on the front-end but has new versions
|
||||
/// that have yet to be published.
|
||||
/// </param>
|
||||
/// <param name="validateContent">If true this will validate each content item before trying to publish it, if validation fails it will not be published.</param>
|
||||
/// <returns></returns>
|
||||
internal abstract IEnumerable<Attempt<PublishStatus>> PublishWithChildrenInternal(
|
||||
IEnumerable<IContent> content, int userId, bool includeUnpublishedDocuments = true, bool validateContent = false);
|
||||
|
||||
internal abstract IEnumerable<Attempt<PublishStatus>> UnPublishInternal(IEnumerable<IContent> content, int userId);
|
||||
|
||||
public abstract bool Publish(IContent content, int userId);
|
||||
public abstract bool PublishWithChildren(IEnumerable<IContent> content, int userId);
|
||||
public abstract bool UnPublish(IContent content, int userId);
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Publishing
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to publish</param>
|
||||
/// <param name="userId">Id of the User issueing the publish operation</param>
|
||||
internal override Attempt<PublishStatus> PublishInternal(IContent content, int userId)
|
||||
internal Attempt<PublishStatus> PublishInternal(IContent content, int userId)
|
||||
{
|
||||
if (Publishing.IsRaisedEventCancelled(new PublishEventArgs<IContent>(content), this))
|
||||
{
|
||||
@@ -85,8 +85,7 @@ namespace Umbraco.Core.Publishing
|
||||
/// By default this is set to true which means that it will publish any content item in the list that is completely unpublished and
|
||||
/// not visible on the front-end. If set to false, this will only publish content that is live on the front-end but has new versions
|
||||
/// that have yet to be published.
|
||||
/// </param>
|
||||
/// <param name="validateContent">If true this will validate each content item before trying to publish it, if validation fails it will not be published.</param>
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This method becomes complex once we start to be able to cancel events or stop publishing a content item in any way because if a
|
||||
@@ -99,8 +98,8 @@ namespace Umbraco.Core.Publishing
|
||||
/// level and so on. If we detect that the above rule applies when the document publishing is cancelled we'll add it to the list of
|
||||
/// parentsIdsCancelled so that it's children don't get published.
|
||||
/// </remarks>
|
||||
internal override IEnumerable<Attempt<PublishStatus>> PublishWithChildrenInternal(
|
||||
IEnumerable<IContent> content, int userId, bool includeUnpublishedDocuments = true, bool validateContent = false)
|
||||
internal IEnumerable<Attempt<PublishStatus>> PublishWithChildrenInternal(
|
||||
IEnumerable<IContent> content, int userId, bool includeUnpublishedDocuments = true)
|
||||
{
|
||||
var statuses = new List<Attempt<PublishStatus>>();
|
||||
|
||||
@@ -163,7 +162,7 @@ namespace Umbraco.Core.Publishing
|
||||
}
|
||||
|
||||
//Check if the content is valid if the flag is set to check
|
||||
if (validateContent && !item.IsValid())
|
||||
if (!item.IsValid())
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published because some of it's content is not passing validation rules.",
|
||||
@@ -322,7 +321,7 @@ namespace Umbraco.Core.Publishing
|
||||
/// <param name="content">An enumerable list of <see cref="IContent"/></param>
|
||||
/// <param name="userId">Id of the User issueing the unpublish operation</param>
|
||||
/// <returns>A list of publish statuses</returns>
|
||||
internal override IEnumerable<Attempt<PublishStatus>> UnPublishInternal(IEnumerable<IContent> content, int userId)
|
||||
internal IEnumerable<Attempt<PublishStatus>> UnPublishInternal(IEnumerable<IContent> content, int userId)
|
||||
{
|
||||
var result = new List<Attempt<PublishStatus>>();
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Services
|
||||
public class ContentService : IContentService
|
||||
{
|
||||
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
|
||||
private readonly BasePublishingStrategy _publishingStrategy;
|
||||
private readonly IPublishingStrategy _publishingStrategy;
|
||||
private readonly RepositoryFactory _repositoryFactory;
|
||||
|
||||
public ContentService()
|
||||
@@ -43,23 +43,16 @@ namespace Umbraco.Core.Services
|
||||
: this(provider, repositoryFactory, new PublishingStrategy())
|
||||
{ }
|
||||
|
||||
[Obsolete("This contructor is no longer supported, use the other constructor accepting a BasePublishginStrategy object instead")]
|
||||
public ContentService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IPublishingStrategy publishingStrategy)
|
||||
{
|
||||
_uowProvider = provider;
|
||||
_publishingStrategy = publishingStrategy as BasePublishingStrategy;
|
||||
if (_publishingStrategy == null)
|
||||
throw new InvalidOperationException("publishingStrategy must be an instance of " + typeof(BasePublishingStrategy).Name);
|
||||
if (provider == null) throw new ArgumentNullException("provider");
|
||||
if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory");
|
||||
if (publishingStrategy == null) throw new ArgumentNullException("publishingStrategy");
|
||||
_uowProvider = provider;
|
||||
_publishingStrategy = publishingStrategy;
|
||||
_repositoryFactory = repositoryFactory;
|
||||
}
|
||||
|
||||
public ContentService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, BasePublishingStrategy publishingStrategy)
|
||||
{
|
||||
_uowProvider = provider;
|
||||
_publishingStrategy = publishingStrategy;
|
||||
_repositoryFactory = repositoryFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IContent"/> object using the alias of the <see cref="IContentType"/>
|
||||
/// that this Content is based on.
|
||||
@@ -477,7 +470,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
public bool RePublishAll(int userId = 0)
|
||||
{
|
||||
return RePublishAllDo(false, userId);
|
||||
return RePublishAllDo(userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -488,7 +481,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
public bool Publish(IContent content, int userId = 0)
|
||||
{
|
||||
var result = SaveAndPublishDo(content, false, userId);
|
||||
var result = SaveAndPublishDo(content, userId);
|
||||
return result.Success;
|
||||
}
|
||||
|
||||
@@ -500,7 +493,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
public bool PublishWithChildren(IContent content, int userId = 0)
|
||||
{
|
||||
var result = PublishWithChildrenDo(content, false, userId);
|
||||
var result = PublishWithChildrenDo(content, userId);
|
||||
|
||||
//This used to just return false only when the parent content failed, otherwise would always return true so we'll
|
||||
// do the same thing for the moment
|
||||
@@ -527,7 +520,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
public bool SaveAndPublish(IContent content, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
var result = SaveAndPublishDo(content, false, userId, raiseEvents);
|
||||
var result = SaveAndPublishDo(content, userId, raiseEvents);
|
||||
return result.Success;
|
||||
}
|
||||
|
||||
@@ -1063,67 +1056,41 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
#region Internal Methods
|
||||
/// <summary>
|
||||
/// Internal method to Re-Publishes all Content for legacy purposes.
|
||||
/// </summary>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will not update the cache.</param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
internal bool RePublishAll(bool omitCacheRefresh = true, int userId = 0)
|
||||
{
|
||||
return RePublishAllDo(omitCacheRefresh, userId);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal method that Publishes a single <see cref="IContent"/> object for legacy purposes.
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish</param>
|
||||
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache.</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
internal Attempt<PublishStatus> Publish(IContent content, bool omitCacheRefresh = true, int userId = 0)
|
||||
internal Attempt<PublishStatus> PublishInternal(IContent content, int userId = 0)
|
||||
{
|
||||
return SaveAndPublishDo(content, omitCacheRefresh, userId);
|
||||
return SaveAndPublishDo(content, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal method that Publishes a <see cref="IContent"/> object and all its children for legacy purposes.
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
|
||||
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache.</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="includeUnpublished">If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published</param>
|
||||
/// <param name="validateContent">If true this will validate the content before publishing</param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
internal IEnumerable<Attempt<PublishStatus>> PublishWithChildren(
|
||||
IContent content, bool omitCacheRefresh = true, int userId = 0, bool includeUnpublished = false, bool validateContent = false)
|
||||
internal IEnumerable<Attempt<PublishStatus>> PublishWithChildrenInternal(
|
||||
IContent content, int userId = 0, bool includeUnpublished = false)
|
||||
{
|
||||
return PublishWithChildrenDo(content, omitCacheRefresh, userId, includeUnpublished, validateContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal method that UnPublishes a single <see cref="IContent"/> object for legacy purposes.
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish</param>
|
||||
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will not update the cache.</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <returns>True if unpublishing succeeded, otherwise False</returns>
|
||||
internal bool UnPublish(IContent content, bool omitCacheRefresh = true, int userId = 0)
|
||||
{
|
||||
return UnPublishDo(content, omitCacheRefresh, userId);
|
||||
return PublishWithChildrenDo(content, userId, includeUnpublished);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves and Publishes a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to save and publish</param>
|
||||
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache.</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise save events.</param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
internal Attempt<PublishStatus> SaveAndPublish(IContent content, bool omitCacheRefresh = true, int userId = 0, bool raiseEvents = true)
|
||||
internal Attempt<PublishStatus> SaveAndPublishInternal(IContent content, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
return SaveAndPublishDo(content, omitCacheRefresh, userId, raiseEvents);
|
||||
return SaveAndPublishDo(content, userId, raiseEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1150,9 +1117,8 @@ namespace Umbraco.Core.Services
|
||||
/// Re-Publishes all Content
|
||||
/// </summary>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will update the cache.</param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
private bool RePublishAllDo(bool omitCacheRefresh = false, int userId = 0)
|
||||
private bool RePublishAllDo(int userId = 0)
|
||||
{
|
||||
var list = new List<IContent>();
|
||||
var updated = new List<IContent>();
|
||||
@@ -1198,9 +1164,8 @@ namespace Umbraco.Core.Services
|
||||
: Convert.ToInt32(uow.Database.Insert(poco));
|
||||
}
|
||||
}
|
||||
//Updating content to published state is finished, so we fire event through PublishingStrategy to have cache updated
|
||||
if (omitCacheRefresh == false)
|
||||
_publishingStrategy.PublishingFinalized(updated, true);
|
||||
|
||||
_publishingStrategy.PublishingFinalized(updated, true);
|
||||
}
|
||||
|
||||
Audit.Add(AuditTypes.Publish, "RePublish All performed by user", userId, -1);
|
||||
@@ -1212,17 +1177,15 @@ namespace Umbraco.Core.Services
|
||||
/// Publishes a <see cref="IContent"/> object and all its children
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
|
||||
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="includeUnpublished">If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published</param>
|
||||
/// <param name="validateContent">If set to true will ensure the content is valid before publishing</param>
|
||||
/// <param name="includeUnpublished">If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published</param>
|
||||
/// <returns>
|
||||
/// A list of publish statues. If the parent document is not valid or cannot be published because it's parent(s) is not published
|
||||
/// then the list will only contain one status item, otherwise it will contain status items for it and all of it's descendants that
|
||||
/// are to be published.
|
||||
/// </returns>
|
||||
private IEnumerable<Attempt<PublishStatus>> PublishWithChildrenDo(
|
||||
IContent content, bool omitCacheRefresh = false, int userId = 0, bool includeUnpublished = false, bool validateContent = false)
|
||||
IContent content, int userId = 0, bool includeUnpublished = false)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
|
||||
@@ -1257,8 +1220,10 @@ namespace Umbraco.Core.Services
|
||||
list.Add(content); //include parent item
|
||||
list.AddRange(GetDescendants(content));
|
||||
|
||||
var internalStrategy = (PublishingStrategy)_publishingStrategy;
|
||||
|
||||
//Publish and then update the database with new status
|
||||
var publishedOutcome = _publishingStrategy.PublishWithChildrenInternal(list, userId, includeUnpublished, validateContent).ToArray();
|
||||
var publishedOutcome = internalStrategy.PublishWithChildrenInternal(list, userId, includeUnpublished).ToArray();
|
||||
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateContentRepository(uow))
|
||||
@@ -1288,8 +1253,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
//Save xml to db and call following method to fire event:
|
||||
if (omitCacheRefresh == false)
|
||||
_publishingStrategy.PublishingFinalized(updated, false);
|
||||
_publishingStrategy.PublishingFinalized(updated, false);
|
||||
|
||||
Audit.Add(AuditTypes.Publish, "Publish with Children performed by user", userId, content.Id);
|
||||
|
||||
@@ -1334,11 +1298,10 @@ namespace Umbraco.Core.Services
|
||||
/// Saves and Publishes a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to save and publish</param>
|
||||
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise save events.</param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
private Attempt<PublishStatus> SaveAndPublishDo(IContent content, bool omitCacheRefresh = false, int userId = 0, bool raiseEvents = true)
|
||||
private Attempt<PublishStatus> SaveAndPublishDo(IContent content, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
if(raiseEvents)
|
||||
{
|
||||
@@ -1372,8 +1335,9 @@ namespace Umbraco.Core.Services
|
||||
publishStatus.StatusType = PublishStatusType.FailedContentInvalid;
|
||||
}
|
||||
|
||||
var internalStrategy = (PublishingStrategy) _publishingStrategy;
|
||||
//Publish and then update the database with new status
|
||||
var publishResult = _publishingStrategy.PublishInternal(content, userId);
|
||||
var publishResult = internalStrategy.PublishInternal(content, userId);
|
||||
//set our publish status to the publish result
|
||||
publishStatus.StatusType = publishResult.Result.StatusType;
|
||||
|
||||
@@ -1430,13 +1394,13 @@ namespace Umbraco.Core.Services
|
||||
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false), this);
|
||||
|
||||
//Save xml to db and call following method to fire event through PublishingStrategy to update cache
|
||||
if (published && omitCacheRefresh == false)
|
||||
if (published)
|
||||
{
|
||||
_publishingStrategy.PublishingFinalized(content);
|
||||
}
|
||||
|
||||
//We need to check if children and their publish state to ensure that we 'republish' content that was previously published
|
||||
if (published && omitCacheRefresh == false && previouslyPublished == false && HasChildren(content.Id))
|
||||
if (published && previouslyPublished == false && HasChildren(content.Id))
|
||||
{
|
||||
var descendants = GetPublishedDescendants(content);
|
||||
|
||||
|
||||
47
src/Umbraco.Core/Sync/ConfigServerRegistrar.cs
Normal file
47
src/Umbraco.Core/Sync/ConfigServerRegistrar.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// A registrar that uses the legacy xml configuration in umbracoSettings to get a list of defined server nodes
|
||||
/// </summary>
|
||||
internal class ConfigServerRegistrar : IServerRegistrar
|
||||
{
|
||||
private readonly XmlNode _xmlServers;
|
||||
|
||||
public ConfigServerRegistrar()
|
||||
: this(UmbracoSettings.DistributionServers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal ConfigServerRegistrar(XmlNode xmlServers)
|
||||
{
|
||||
_xmlServers = xmlServers;
|
||||
}
|
||||
|
||||
private List<IServerRegistration> _addresses;
|
||||
|
||||
public IEnumerable<IServerRegistration> Registrations
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_addresses == null)
|
||||
{
|
||||
_addresses = new List<IServerRegistration>();
|
||||
var nodes = _xmlServers.SelectNodes("./server");
|
||||
foreach (XmlNode n in nodes)
|
||||
{
|
||||
_addresses.Add(new ConfigServerRegistration(n));
|
||||
}
|
||||
}
|
||||
return _addresses;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/Umbraco.Core/Sync/ConfigServerRegistration.cs
Normal file
29
src/Umbraco.Core/Sync/ConfigServerRegistration.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Xml;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// A server registration based on the legacy umbraco xml configuration in umbracoSettings
|
||||
/// </summary>
|
||||
internal class ConfigServerRegistration : IServerRegistration
|
||||
{
|
||||
|
||||
public ConfigServerRegistration(XmlNode n)
|
||||
{
|
||||
var webServicesUrl = IOHelper.ResolveUrl(SystemDirectories.WebServices);
|
||||
|
||||
var protocol = GlobalSettings.UseSSL ? "https" : "http";
|
||||
if (n.Attributes.GetNamedItem("forceProtocol") != null && !string.IsNullOrEmpty(n.Attributes.GetNamedItem("forceProtocol").Value))
|
||||
protocol = n.Attributes.GetNamedItem("forceProtocol").Value;
|
||||
var domain = XmlHelper.GetNodeValue(n);
|
||||
if (n.Attributes.GetNamedItem("forcePortnumber") != null && !string.IsNullOrEmpty(n.Attributes.GetNamedItem("forcePortnumber").Value))
|
||||
domain += string.Format(":{0}", n.Attributes.GetNamedItem("forcePortnumber").Value);
|
||||
ServerAddress = string.Format("{0}://{1}{2}/cacheRefresher.asmx", protocol, domain, webServicesUrl);
|
||||
}
|
||||
|
||||
public string ServerAddress { get; private set; }
|
||||
|
||||
}
|
||||
}
|
||||
401
src/Umbraco.Core/Sync/DefaultServerMessenger.cs
Normal file
401
src/Umbraco.Core/Sync/DefaultServerMessenger.cs
Normal file
@@ -0,0 +1,401 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Web.Script.Serialization;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// The default server messenger that uses web services to keep servers in sync
|
||||
/// </summary>
|
||||
internal class DefaultServerMessenger : IServerMessenger
|
||||
{
|
||||
private readonly string _login;
|
||||
private readonly string _password;
|
||||
private readonly bool _useDistributedCalls;
|
||||
|
||||
/// <summary>
|
||||
/// Without a username/password all distribuion will be disabled
|
||||
/// </summary>
|
||||
internal DefaultServerMessenger()
|
||||
{
|
||||
_useDistributedCalls = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Distribution will be enabled based on the umbraco config setting.
|
||||
/// </summary>
|
||||
/// <param name="login"></param>
|
||||
/// <param name="password"></param>
|
||||
internal DefaultServerMessenger(string login, string password)
|
||||
{
|
||||
_useDistributedCalls = UmbracoSettings.UseDistributedCalls;
|
||||
_login = login;
|
||||
_password = password;
|
||||
}
|
||||
|
||||
public void PerformRefresh<T>(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher,Func<T, int> getNumericId, params T[] instances)
|
||||
{
|
||||
if (servers == null) throw new ArgumentNullException("servers");
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
|
||||
//copy local
|
||||
var idGetter = getNumericId;
|
||||
|
||||
MessageSeversForManyObjects(servers, refresher, MessageType.RefreshById,
|
||||
x => idGetter(x),
|
||||
instances);
|
||||
}
|
||||
|
||||
public void PerformRefresh<T>(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, Func<T, Guid> getGuidId, params T[] instances)
|
||||
{
|
||||
if (servers == null) throw new ArgumentNullException("servers");
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
|
||||
//copy local
|
||||
var idGetter = getGuidId;
|
||||
|
||||
MessageSeversForManyObjects(servers, refresher, MessageType.RefreshById,
|
||||
x => idGetter(x),
|
||||
instances);
|
||||
}
|
||||
|
||||
public void PerformRemove<T>(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, Func<T, int> getNumericId, params T[] instances)
|
||||
{
|
||||
if (servers == null) throw new ArgumentNullException("servers");
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
|
||||
//copy local
|
||||
var idGetter = getNumericId;
|
||||
|
||||
MessageSeversForManyObjects(servers, refresher, MessageType.RemoveById,
|
||||
x => idGetter(x),
|
||||
instances);
|
||||
}
|
||||
|
||||
public void PerformRemove(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, params int[] numericIds)
|
||||
{
|
||||
if (servers == null) throw new ArgumentNullException("servers");
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
|
||||
MessageSeversForManyIds(servers, refresher, MessageType.RemoveById, numericIds.Cast<object>());
|
||||
}
|
||||
|
||||
public void PerformRefresh(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, params int[] numericIds)
|
||||
{
|
||||
if (servers == null) throw new ArgumentNullException("servers");
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
|
||||
MessageSeversForManyIds(servers, refresher, MessageType.RefreshById, numericIds.Cast<object>());
|
||||
}
|
||||
|
||||
public void PerformRefresh(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, params Guid[] guidIds)
|
||||
{
|
||||
if (servers == null) throw new ArgumentNullException("servers");
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
|
||||
MessageSeversForManyIds(servers, refresher, MessageType.RefreshById, guidIds.Cast<object>());
|
||||
}
|
||||
|
||||
public void PerformRefreshAll(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher)
|
||||
{
|
||||
MessageSeversForManyIds(servers, refresher, MessageType.RefreshAll, Enumerable.Empty<object>().ToArray());
|
||||
}
|
||||
|
||||
private void InvokeMethodOnRefresherInstance<T>(ICacheRefresher refresher, MessageType dispatchType, Func<T, object> getId, IEnumerable<T> instances)
|
||||
{
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
|
||||
var stronglyTypedRefresher = refresher as ICacheRefresher<T>;
|
||||
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
//if we are not, then just invoke the call on the cache refresher
|
||||
switch (dispatchType)
|
||||
{
|
||||
case MessageType.RefreshAll:
|
||||
refresher.RefreshAll();
|
||||
break;
|
||||
case MessageType.RefreshById:
|
||||
if (stronglyTypedRefresher != null)
|
||||
{
|
||||
stronglyTypedRefresher.Refresh(instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
var id = getId(instance);
|
||||
if (id is int)
|
||||
{
|
||||
refresher.Refresh((int)id);
|
||||
}
|
||||
else if (id is Guid)
|
||||
{
|
||||
refresher.Refresh((Guid)id);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("The id must be either an int or a Guid");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MessageType.RemoveById:
|
||||
if (stronglyTypedRefresher != null)
|
||||
{
|
||||
stronglyTypedRefresher.Remove(instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
var id = getId(instance);
|
||||
refresher.Refresh((int)id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InvokeMethodOnRefresherInstance(ICacheRefresher refresher, MessageType dispatchType, IEnumerable<object> ids)
|
||||
{
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
|
||||
//if it is a refresh all we'll do it here since ids will be null or empty
|
||||
if (dispatchType == MessageType.RefreshAll)
|
||||
{
|
||||
refresher.RefreshAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var id in ids)
|
||||
{
|
||||
//if we are not, then just invoke the call on the cache refresher
|
||||
switch (dispatchType)
|
||||
{
|
||||
case MessageType.RefreshById:
|
||||
if (id is int)
|
||||
{
|
||||
refresher.Refresh((int)id);
|
||||
}
|
||||
else if (id is Guid)
|
||||
{
|
||||
refresher.Refresh((Guid)id);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("The id must be either an int or a Guid");
|
||||
}
|
||||
|
||||
break;
|
||||
case MessageType.RemoveById:
|
||||
refresher.Remove((int)id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void MessageSeversForManyObjects<T>(
|
||||
IEnumerable<IServerRegistration> servers,
|
||||
ICacheRefresher refresher,
|
||||
MessageType dispatchType,
|
||||
Func<T, object> getId,
|
||||
IEnumerable<T> instances)
|
||||
{
|
||||
if (servers == null) throw new ArgumentNullException("servers");
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
|
||||
//Now, check if we are using Distrubuted calls. If there are no servers in the list then we
|
||||
// can definitely not distribute.
|
||||
if (!_useDistributedCalls || !servers.Any())
|
||||
{
|
||||
//if we are not, then just invoke the call on the cache refresher
|
||||
InvokeMethodOnRefresherInstance(refresher, dispatchType, getId, instances);
|
||||
return;
|
||||
}
|
||||
|
||||
//if we are distributing calls then we'll need to do it by id
|
||||
MessageSeversForManyIds(servers, refresher, dispatchType, instances.Select(getId));
|
||||
}
|
||||
|
||||
private void MessageSeversForManyIds(
|
||||
IEnumerable<IServerRegistration> servers,
|
||||
ICacheRefresher refresher,
|
||||
MessageType dispatchType,
|
||||
IEnumerable<object> ids)
|
||||
{
|
||||
if (servers == null) throw new ArgumentNullException("servers");
|
||||
if (refresher == null) throw new ArgumentNullException("refresher");
|
||||
Type arrayType = null;
|
||||
foreach (var id in ids)
|
||||
{
|
||||
if (!(id is int) && (!(id is Guid)))
|
||||
throw new ArgumentException("The id must be either an int or a Guid");
|
||||
if (arrayType == null)
|
||||
arrayType = id.GetType();
|
||||
if (arrayType != id.GetType())
|
||||
throw new ArgumentException("The array must contain the same type of " + arrayType);
|
||||
}
|
||||
|
||||
//Now, check if we are using Distrubuted calls. If there are no servers in the list then we
|
||||
// can definitely not distribute.
|
||||
if (!_useDistributedCalls || !servers.Any())
|
||||
{
|
||||
//if we are not, then just invoke the call on the cache refresher
|
||||
InvokeMethodOnRefresherInstance(refresher, dispatchType, ids);
|
||||
return;
|
||||
}
|
||||
|
||||
//We are using distributed calls, so lets make them...
|
||||
try
|
||||
{
|
||||
using (var cacheRefresher = new ServerSyncWebServiceClient())
|
||||
{
|
||||
var asyncResultsList = new List<IAsyncResult>();
|
||||
|
||||
LogStartDispatch();
|
||||
|
||||
// Go through each configured node submitting a request asynchronously
|
||||
foreach (var n in servers)
|
||||
{
|
||||
//set the server address
|
||||
cacheRefresher.Url = n.ServerAddress;
|
||||
|
||||
// Add the returned WaitHandle to the list for later checking
|
||||
switch (dispatchType)
|
||||
{
|
||||
case MessageType.RefreshAll:
|
||||
asyncResultsList.Add(
|
||||
cacheRefresher.BeginRefreshAll(
|
||||
refresher.UniqueIdentifier, _login, _password, null, null));
|
||||
break;
|
||||
case MessageType.RefreshById:
|
||||
if (arrayType == typeof(int))
|
||||
{
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var jsonIds = serializer.Serialize(ids.Cast<int>().ToArray());
|
||||
//we support bulk loading of Integers
|
||||
var result = cacheRefresher.BeginRefreshByIds(refresher.UniqueIdentifier, jsonIds, _login, _password, null, null);
|
||||
asyncResultsList.Add(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
//we don't currently support bulk loading of GUIDs (not even sure if we have any Guid ICacheRefreshers)
|
||||
//so we'll just iterate
|
||||
asyncResultsList.AddRange(
|
||||
ids.Select(i => cacheRefresher.BeginRefreshByGuid(
|
||||
refresher.UniqueIdentifier, (Guid) i, _login, _password, null, null)));
|
||||
}
|
||||
|
||||
break;
|
||||
case MessageType.RemoveById:
|
||||
//we don't currently support bulk removing so we'll iterate
|
||||
asyncResultsList.AddRange(
|
||||
ids.Select(i => cacheRefresher.BeginRemoveById(
|
||||
refresher.UniqueIdentifier, (int)i, _login, _password, null, null)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
List<WaitHandle> waitHandlesList;
|
||||
var asyncResults = GetAsyncResults(asyncResultsList, out waitHandlesList);
|
||||
|
||||
var errorCount = 0;
|
||||
|
||||
// Once for each WaitHandle that we have, wait for a response and log it
|
||||
// We're previously submitted all these requests effectively in parallel and will now retrieve responses on a FIFO basis
|
||||
foreach (var t in asyncResults)
|
||||
{
|
||||
var handleIndex = WaitHandle.WaitAny(waitHandlesList.ToArray(), TimeSpan.FromSeconds(15));
|
||||
|
||||
try
|
||||
{
|
||||
// Find out if the call succeeded
|
||||
switch (dispatchType)
|
||||
{
|
||||
case MessageType.RefreshAll:
|
||||
cacheRefresher.EndRefreshAll(t);
|
||||
break;
|
||||
case MessageType.RefreshById:
|
||||
if (arrayType == typeof(int))
|
||||
{
|
||||
cacheRefresher.EndRefreshById(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheRefresher.EndRefreshByGuid(t);
|
||||
}
|
||||
break;
|
||||
case MessageType.RemoveById:
|
||||
cacheRefresher.EndRemoveById(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
LogDispatchNodeError(ex);
|
||||
|
||||
errorCount++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogDispatchNodeError(ex);
|
||||
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
LogDispatchBatchResult(errorCount);
|
||||
}
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
LogDispatchBatchError(ee);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IAsyncResult> GetAsyncResults(List<IAsyncResult> asyncResultsList, out List<WaitHandle> waitHandlesList)
|
||||
{
|
||||
var asyncResults = asyncResultsList.ToArray();
|
||||
waitHandlesList = new List<WaitHandle>();
|
||||
foreach (var asyncResult in asyncResults)
|
||||
{
|
||||
waitHandlesList.Add(asyncResult.AsyncWaitHandle);
|
||||
}
|
||||
return asyncResults;
|
||||
}
|
||||
|
||||
private void LogDispatchBatchError(Exception ee)
|
||||
{
|
||||
LogHelper.Error<DefaultServerMessenger>("Error refreshing distributed list", ee);
|
||||
}
|
||||
|
||||
private void LogDispatchBatchResult(int errorCount)
|
||||
{
|
||||
LogHelper.Debug<DefaultServerMessenger>(string.Format("Distributed server push completed with {0} nodes reporting an error", errorCount == 0 ? "no" : errorCount.ToString(CultureInfo.InvariantCulture)));
|
||||
}
|
||||
|
||||
private void LogDispatchNodeError(Exception ex)
|
||||
{
|
||||
LogHelper.Error<DefaultServerMessenger>("Error refreshing a node in the distributed list", ex);
|
||||
}
|
||||
|
||||
private void LogDispatchNodeError(WebException ex)
|
||||
{
|
||||
string url = (ex.Response != null) ? ex.Response.ResponseUri.ToString() : "invalid url (responseUri null)";
|
||||
LogHelper.Error<DefaultServerMessenger>("Error refreshing a node in the distributed list, URI attempted: " + url, ex);
|
||||
}
|
||||
|
||||
private void LogStartDispatch()
|
||||
{
|
||||
LogHelper.Info<DefaultServerMessenger>("Submitting calls to distributed servers");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
18
src/Umbraco.Core/Sync/ICacheRefresher.cs
Normal file
18
src/Umbraco.Core/Sync/ICacheRefresher.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly type cache refresher that is able to refresh cache of real instances of objects as well as IDs
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <remarks>
|
||||
/// This is much better for performance when we're not running in a load balanced environment so we can refresh the cache
|
||||
/// against a already resolved object instead of looking the object back up by id.
|
||||
/// </remarks>
|
||||
interface ICacheRefresher<T> : ICacheRefresher
|
||||
{
|
||||
void Refresh(T instance);
|
||||
void Remove(T instance);
|
||||
}
|
||||
}
|
||||
74
src/Umbraco.Core/Sync/IServerMessenger.cs
Normal file
74
src/Umbraco.Core/Sync/IServerMessenger.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a server messenger for server sync and distrubuted cache
|
||||
/// </summary>
|
||||
internal interface IServerMessenger
|
||||
{
|
||||
/// <summary>
|
||||
/// Performs a sync against all instance objects
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="servers">The servers to sync against</param>
|
||||
/// <param name="refresher"></param>
|
||||
/// <param name="getNumericId">A delegate to return the Id for each instance to be used to sync to other servers</param>
|
||||
/// <param name="instances"></param>
|
||||
void PerformRefresh<T>(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, Func<T, int> getNumericId, params T[] instances);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a sync against all instance objects
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="servers">The servers to sync against</param>
|
||||
/// <param name="refresher"></param>
|
||||
/// <param name="getGuidId">A delegate to return the Id for each instance to be used to sync to other servers</param>
|
||||
/// <param name="instances"></param>
|
||||
void PerformRefresh<T>(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, Func<T, Guid> getGuidId, params T[] instances);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the cache for the specified items
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="servers"></param>
|
||||
/// <param name="refresher"></param>
|
||||
/// <param name="getNumericId">A delegate to return the Id for each instance to be used to sync to other servers</param>
|
||||
/// <param name="instances"></param>
|
||||
void PerformRemove<T>(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, Func<T, int> getNumericId, params T[] instances);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the cache for the specified items
|
||||
/// </summary>
|
||||
/// <param name="servers"></param>
|
||||
/// <param name="refresher"></param>
|
||||
/// <param name="numericIds"></param>
|
||||
void PerformRemove(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, params int[] numericIds);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a sync against all Ids
|
||||
/// </summary>
|
||||
/// <param name="servers">The servers to sync against</param>
|
||||
/// <param name="refresher"></param>
|
||||
/// <param name="numericIds"></param>
|
||||
void PerformRefresh(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, params int[] numericIds);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a sync against all Ids
|
||||
/// </summary>
|
||||
/// <param name="servers">The servers to sync against</param>
|
||||
/// <param name="refresher"></param>
|
||||
/// <param name="guidIds"></param>
|
||||
void PerformRefresh(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher, params Guid[] guidIds);
|
||||
|
||||
/// <summary>
|
||||
/// Performs entire cache refresh for a specified refresher
|
||||
/// </summary>
|
||||
/// <param name="servers"></param>
|
||||
/// <param name="refresher"></param>
|
||||
void PerformRefreshAll(IEnumerable<IServerRegistration> servers, ICacheRefresher refresher);
|
||||
}
|
||||
|
||||
}
|
||||
12
src/Umbraco.Core/Sync/IServerRegistrar.cs
Normal file
12
src/Umbraco.Core/Sync/IServerRegistrar.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface to expose a list of server registrations for server syncing
|
||||
/// </summary>
|
||||
internal interface IServerRegistrar
|
||||
{
|
||||
IEnumerable<IServerRegistration> Registrations { get; }
|
||||
}
|
||||
}
|
||||
10
src/Umbraco.Core/Sync/IServerRegistration.cs
Normal file
10
src/Umbraco.Core/Sync/IServerRegistration.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface exposing a server address to use for server syncing
|
||||
/// </summary>
|
||||
internal interface IServerRegistration
|
||||
{
|
||||
string ServerAddress { get; }
|
||||
}
|
||||
}
|
||||
12
src/Umbraco.Core/Sync/MessageType.cs
Normal file
12
src/Umbraco.Core/Sync/MessageType.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// The message type to be used for syncing across servers
|
||||
/// </summary>
|
||||
internal enum MessageType
|
||||
{
|
||||
RefreshAll,
|
||||
RefreshById,
|
||||
RemoveById
|
||||
}
|
||||
}
|
||||
29
src/Umbraco.Core/Sync/ServerMessengerResolver.cs
Normal file
29
src/Umbraco.Core/Sync/ServerMessengerResolver.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// A resolver to return the currently registered IServerMessenger object
|
||||
/// </summary>
|
||||
internal class ServerMessengerResolver : SingleObjectResolverBase<ServerMessengerResolver, IServerMessenger>
|
||||
{
|
||||
internal ServerMessengerResolver(IServerMessenger factory)
|
||||
: base(factory)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used at runtime to set a custom IServerMessenger at app startup
|
||||
/// </summary>
|
||||
/// <param name="serverMessenger"></param>
|
||||
public void SetServerMessenger(IServerMessenger serverMessenger)
|
||||
{
|
||||
Value = serverMessenger;
|
||||
}
|
||||
|
||||
public IServerMessenger Messenger
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/Umbraco.Core/Sync/ServerRegistrarResolver.cs
Normal file
31
src/Umbraco.Core/Sync/ServerRegistrarResolver.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// The resolver to return the currently registered IServerRegistrar object
|
||||
/// </summary>
|
||||
internal class ServerRegistrarResolver : SingleObjectResolverBase<ServerRegistrarResolver, IServerRegistrar>
|
||||
{
|
||||
|
||||
internal ServerRegistrarResolver(IServerRegistrar factory)
|
||||
: base(factory)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used at runtime to set a custom IServerRegistrar at app startup
|
||||
/// </summary>
|
||||
/// <param name="serverRegistrar"></param>
|
||||
public void SetServerRegistrar(IServerRegistrar serverRegistrar)
|
||||
{
|
||||
Value = serverRegistrar;
|
||||
}
|
||||
|
||||
public IServerRegistrar Registrar
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
193
src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs
Normal file
193
src/Umbraco.Core/Sync/ServerSyncWebServiceClient.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Services;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The client Soap service for making distrubuted cache calls between servers
|
||||
/// </summary>
|
||||
[WebServiceBinding(Name = "CacheRefresherSoap", Namespace = "http://umbraco.org/webservices/")]
|
||||
internal class ServerSyncWebServiceClient : System.Web.Services.Protocols.SoapHttpClientProtocol
|
||||
{
|
||||
|
||||
/// <remarks/>
|
||||
public ServerSyncWebServiceClient()
|
||||
{
|
||||
// only set the url if the httpcontext is present, else it's set by the cache dispatcher methods (when using distributed calls)
|
||||
if (System.Web.HttpContext.Current != null)
|
||||
this.Url = "http://" + System.Web.HttpContext.Current.Request.ServerVariables["SERVER_NAME"] + IOHelper.ResolveUrl(SystemDirectories.WebServices) + "/cacheRefresher.asmx";
|
||||
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RefreshAll", RequestNamespace = "http://umbraco.org/webservices/", ResponseNamespace = "http://umbraco.org/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
|
||||
public void RefreshAll(System.Guid uniqueIdentifier, string Login, string Password)
|
||||
{
|
||||
this.Invoke("RefreshAll", new object[] {
|
||||
uniqueIdentifier,
|
||||
Login,
|
||||
Password});
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public System.IAsyncResult BeginRefreshAll(System.Guid uniqueIdentifier, string Login, string Password, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return this.BeginInvoke("RefreshAll", new object[] {
|
||||
uniqueIdentifier,
|
||||
Login,
|
||||
Password}, callback, asyncState);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public void EndRefreshAll(System.IAsyncResult asyncResult)
|
||||
{
|
||||
this.EndInvoke(asyncResult);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RefreshByGuid", RequestNamespace = "http://umbraco.org/webservices/", ResponseNamespace = "http://umbraco.org/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
|
||||
public void RefreshByGuid(System.Guid uniqueIdentifier, System.Guid Id, string Login, string Password)
|
||||
{
|
||||
this.Invoke("RefreshByGuid", new object[] {
|
||||
uniqueIdentifier,
|
||||
Id,
|
||||
Login,
|
||||
Password});
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public System.IAsyncResult BeginRefreshByGuid(System.Guid uniqueIdentifier, System.Guid Id, string Login, string Password, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return this.BeginInvoke("RefreshByGuid", new object[] {
|
||||
uniqueIdentifier,
|
||||
Id,
|
||||
Login,
|
||||
Password}, callback, asyncState);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public void EndRefreshByGuid(System.IAsyncResult asyncResult)
|
||||
{
|
||||
this.EndInvoke(asyncResult);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RefreshById",
|
||||
RequestNamespace = "http://umbraco.org/webservices/",
|
||||
ResponseNamespace = "http://umbraco.org/webservices/",
|
||||
Use = System.Web.Services.Description.SoapBindingUse.Literal,
|
||||
ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
|
||||
public void RefreshById(System.Guid uniqueIdentifier, int Id, string Login, string Password)
|
||||
{
|
||||
this.Invoke("RefreshById", new object[] {
|
||||
uniqueIdentifier,
|
||||
Id,
|
||||
Login,
|
||||
Password});
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public System.IAsyncResult BeginRefreshById(System.Guid uniqueIdentifier, int Id, string Login, string Password, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return this.BeginInvoke("RefreshById", new object[] {
|
||||
uniqueIdentifier,
|
||||
Id,
|
||||
Login,
|
||||
Password}, callback, asyncState);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public void EndRefreshById(System.IAsyncResult asyncResult)
|
||||
{
|
||||
this.EndInvoke(asyncResult);
|
||||
}
|
||||
|
||||
|
||||
/// <remarks/>
|
||||
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RefreshByIds",
|
||||
RequestNamespace = "http://umbraco.org/webservices/",
|
||||
ResponseNamespace = "http://umbraco.org/webservices/",
|
||||
Use = System.Web.Services.Description.SoapBindingUse.Literal,
|
||||
ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
|
||||
public void RefreshByIds(System.Guid uniqueIdentifier, string jsonIds, string Login, string Password)
|
||||
{
|
||||
this.Invoke("RefreshByIds", new object[] {
|
||||
uniqueIdentifier,
|
||||
jsonIds,
|
||||
Login,
|
||||
Password});
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public System.IAsyncResult BeginRefreshByIds(System.Guid uniqueIdentifier, string jsonIds, string Login, string Password, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return this.BeginInvoke("RefreshByIds", new object[] {
|
||||
uniqueIdentifier,
|
||||
jsonIds,
|
||||
Login,
|
||||
Password}, callback, asyncState);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public void EndRefreshByIds(System.IAsyncResult asyncResult)
|
||||
{
|
||||
this.EndInvoke(asyncResult);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <remarks/>
|
||||
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/RemoveById", RequestNamespace = "http://umbraco.org/webservices/", ResponseNamespace = "http://umbraco.org/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
|
||||
public void RemoveById(System.Guid uniqueIdentifier, int Id, string Login, string Password)
|
||||
{
|
||||
this.Invoke("RemoveById", new object[] {
|
||||
uniqueIdentifier,
|
||||
Id,
|
||||
Login,
|
||||
Password});
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public System.IAsyncResult BeginRemoveById(System.Guid uniqueIdentifier, int Id, string Login, string Password, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return this.BeginInvoke("RemoveById", new object[] {
|
||||
uniqueIdentifier,
|
||||
Id,
|
||||
Login,
|
||||
Password}, callback, asyncState);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public void EndRemoveById(System.IAsyncResult asyncResult)
|
||||
{
|
||||
this.EndInvoke(asyncResult);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/GetRefreshers", RequestNamespace = "http://umbraco.org/webservices/", ResponseNamespace = "http://umbraco.org/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
|
||||
public System.Xml.XmlNode GetRefreshers(string Login, string Password)
|
||||
{
|
||||
object[] results = this.Invoke("GetRefreshers", new object[] {
|
||||
Login,
|
||||
Password});
|
||||
return ((System.Xml.XmlNode)(results[0]));
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public System.IAsyncResult BeginGetRefreshers(string Login, string Password, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return this.BeginInvoke("GetRefreshers", new object[] {
|
||||
Login,
|
||||
Password}, callback, asyncState);
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
public System.Xml.XmlNode EndGetRefreshers(System.IAsyncResult asyncResult)
|
||||
{
|
||||
object[] results = this.EndInvoke(asyncResult);
|
||||
return ((System.Xml.XmlNode)(results[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,7 @@
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Web.Helpers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll</HintPath>
|
||||
@@ -73,6 +74,7 @@
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.Razor.2.0.20715.0\lib\net40\System.Web.Razor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.Web.WebPages, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll</HintPath>
|
||||
@@ -667,6 +669,19 @@
|
||||
<Compile Include="Services\MediaService.cs" />
|
||||
<Compile Include="Services\ServiceContext.cs" />
|
||||
<Compile Include="Services\UserService.cs" />
|
||||
<Compile Include="Sync\DefaultServerMessenger.cs" />
|
||||
<Compile Include="Sync\ICacheRefresher.cs" />
|
||||
<Compile Include="Sync\ServerSyncWebServiceClient.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Sync\ConfigServerRegistration.cs" />
|
||||
<Compile Include="Sync\IServerMessenger.cs" />
|
||||
<Compile Include="Sync\IServerRegistrar.cs" />
|
||||
<Compile Include="Sync\IServerRegistration.cs" />
|
||||
<Compile Include="Sync\MessageType.cs" />
|
||||
<Compile Include="Sync\ServerMessengerResolver.cs" />
|
||||
<Compile Include="Sync\ServerRegistrarResolver.cs" />
|
||||
<Compile Include="Sync\ConfigServerRegistrar.cs" />
|
||||
<Compile Include="TypeExtensions.cs" />
|
||||
<Compile Include="ReadLock.cs" />
|
||||
<Compile Include="TypeFinder.cs" />
|
||||
|
||||
Reference in New Issue
Block a user