Completes: U4-2633 Bundle all cache refresher transmissions into a single call per request for much better performance

This commit is contained in:
Shannon
2014-06-08 12:49:20 +02:00
parent ea32776174
commit d0cb27d1c1
11 changed files with 492 additions and 55 deletions

View File

@@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading;
using System.Web;
using System.Web.Script.Serialization;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
@@ -520,7 +521,7 @@ namespace Umbraco.Core.Sync
}
}
private IEnumerable<IAsyncResult> GetAsyncResults(List<IAsyncResult> asyncResultsList, out List<WaitHandle> waitHandlesList)
internal IEnumerable<IAsyncResult> GetAsyncResults(List<IAsyncResult> asyncResultsList, out List<WaitHandle> waitHandlesList)
{
var asyncResults = asyncResultsList.ToArray();
waitHandlesList = new List<WaitHandle>();

View File

@@ -0,0 +1,63 @@
using System;
namespace Umbraco.Core.Sync
{
[Serializable]
public class RefreshInstruction
{
public RefreshMethodType RefreshType { get; set; }
public Guid RefresherId { get; set; }
public Guid GuidId { get; set; }
public int IntId { get; set; }
public string JsonIds { get; set; }
public string JsonPayload { get; set; }
[Serializable]
public enum RefreshMethodType
{
RefreshAll,
RefreshByGuid,
RefreshById,
RefreshByIds,
RefreshByJson,
RemoveById
}
protected bool Equals(RefreshInstruction other)
{
return RefreshType == other.RefreshType && RefresherId.Equals(other.RefresherId) && GuidId.Equals(other.GuidId) && IntId == other.IntId && string.Equals(JsonIds, other.JsonIds) && string.Equals(JsonPayload, other.JsonPayload);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((RefreshInstruction) obj);
}
public override int GetHashCode()
{
unchecked
{
int hashCode = (int) RefreshType;
hashCode = (hashCode*397) ^ RefresherId.GetHashCode();
hashCode = (hashCode*397) ^ GuidId.GetHashCode();
hashCode = (hashCode*397) ^ IntId;
hashCode = (hashCode*397) ^ (JsonIds != null ? JsonIds.GetHashCode() : 0);
hashCode = (hashCode*397) ^ (JsonPayload != null ? JsonPayload.GetHashCode() : 0);
return hashCode;
}
}
public static bool operator ==(RefreshInstruction left, RefreshInstruction right)
{
return Equals(left, right);
}
public static bool operator !=(RefreshInstruction left, RefreshInstruction right)
{
return !Equals(left, right);
}
}
}

View File

@@ -4,7 +4,6 @@ using Umbraco.Core.IO;
namespace Umbraco.Core.Sync
{
/// <summary>
/// The client Soap service for making distrubuted cache calls between servers
/// </summary>
@@ -21,6 +20,31 @@ namespace Umbraco.Core.Sync
}
/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://umbraco.org/webservices/BulkRefresh", 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 BulkRefresh(RefreshInstruction[] instructions, string login, string password)
{
this.Invoke("BulkRefresh", new object[] {
instructions,
login,
password});
}
/// <remarks/>
public System.IAsyncResult BeginBulkRefresh(RefreshInstruction[] instructions, string login, string password, System.AsyncCallback callback, object asyncState)
{
return this.BeginInvoke("BulkRefresh", new object[] {
instructions,
login,
password}, callback, asyncState);
}
/// <remarks/>
public void EndBulkRefresh(System.IAsyncResult asyncResult)
{
this.EndInvoke(asyncResult);
}
/// <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)

View File

@@ -830,6 +830,7 @@
<Compile Include="Standalone\StandaloneCoreBootManager.cs" />
<Compile Include="Strings\ContentBaseExtensions.cs" />
<Compile Include="Strings\Diff.cs" />
<Compile Include="Sync\RefreshInstruction.cs" />
<Compile Include="TopologicalSorter.cs" />
<Compile Include="Strings\DefaultUrlSegmentProvider.cs" />
<Compile Include="Strings\IUrlSegmentProvider.cs" />

View File

@@ -224,7 +224,7 @@
</scheduledTasks>
<!-- distributed calls make umbraco use webservices to handle cache refreshing -->
<distributedCall enable="false">
<distributedCall enable="true">
<!-- the id of the user who's making the calls -->
<!-- needed for security, umbraco will automatically look up correct login and passwords -->
<user>0</user>
@@ -233,6 +233,7 @@
<!-- you can also add optional attributes to force a protocol or port number (see #2) -->
<!-- <server>127.0.0.1</server>-->
<!-- <server forceProtocol="http|https" forcePortnumber="80|443">127.0.0.1</server>-->
<server forcePortnumber="7100">localhost</server>
</servers>
</distributedCall>

View File

@@ -0,0 +1,271 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.UI.WebControls;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Sync;
using umbraco.interfaces;
namespace Umbraco.Web
{
internal class BatchedServerMessenger : DefaultServerMessenger
{
internal BatchedServerMessenger()
{
UmbracoModule.EndRequest += UmbracoModule_EndRequest;
}
internal BatchedServerMessenger(string login, string password) : base(login, password)
{
UmbracoModule.EndRequest += UmbracoModule_EndRequest;
}
internal BatchedServerMessenger(string login, string password, bool useDistributedCalls) : base(login, password, useDistributedCalls)
{
UmbracoModule.EndRequest += UmbracoModule_EndRequest;
}
public BatchedServerMessenger(Func<Tuple<string, string>> getUserNamePasswordDelegate) : base(getUserNamePasswordDelegate)
{
UmbracoModule.EndRequest += UmbracoModule_EndRequest;
}
void UmbracoModule_EndRequest(object sender, EventArgs e)
{
if (HttpContext.Current == null)
{
return;
}
var items = HttpContext.Current.Items[typeof(BatchedServerMessenger).Name] as List<Message>;
if (items != null)
{
var copied = new Message[items.Count];
items.CopyTo(copied);
//now set to null so it get's cleaned up on this request
HttpContext.Current.Items[typeof (BatchedServerMessenger).Name] = null;
SendMessages(copied);
}
}
private class Message
{
public IEnumerable<IServerAddress> Servers { get; set; }
public ICacheRefresher Refresher { get; set; }
public MessageType DispatchType { get; set; }
public IEnumerable<object> Ids { get; set; }
public Type IdArrayType { get; set; }
public string JsonPayload { get; set; }
}
protected override void PerformDistributedCall(
IEnumerable<IServerAddress> servers,
ICacheRefresher refresher,
MessageType dispatchType,
IEnumerable<object> ids = null,
Type idArrayType = null,
string jsonPayload = null)
{
//NOTE: we use UmbracoContext instead of HttpContext.Current because when some web methods run async, the
// HttpContext.Current is null but the UmbracoContext.Current won't be since we manually assign it.
if (UmbracoContext.Current == null || UmbracoContext.Current.HttpContext == null)
{
throw new NotSupportedException("This messenger cannot execute without a valid/current UmbracoContext with an HttpContext assigned");
}
if (UmbracoContext.Current.HttpContext.Items[typeof(BatchedServerMessenger).Name] == null)
{
UmbracoContext.Current.HttpContext.Items[typeof(BatchedServerMessenger).Name] = new List<Message>();
}
var list = (List<Message>)UmbracoContext.Current.HttpContext.Items[typeof(BatchedServerMessenger).Name];
list.Add(new Message
{
DispatchType = dispatchType,
IdArrayType = idArrayType,
Ids = ids,
JsonPayload = jsonPayload,
Refresher = refresher,
Servers = servers
});
}
private RefreshInstruction[] ConvertToInstruction(Message msg)
{
switch (msg.DispatchType)
{
case MessageType.RefreshAll:
return new[]
{
new RefreshInstruction
{
RefreshType = RefreshInstruction.RefreshMethodType.RefreshAll,
RefresherId = msg.Refresher.UniqueIdentifier
}
};
case MessageType.RefreshById:
if (msg.IdArrayType == null)
{
throw new InvalidOperationException("Cannot refresh by id if the idArrayType is null");
}
if (msg.IdArrayType == typeof(int))
{
var serializer = new JavaScriptSerializer();
var jsonIds = serializer.Serialize(msg.Ids.Cast<int>().ToArray());
return new[]
{
new RefreshInstruction
{
JsonIds = jsonIds,
RefreshType = RefreshInstruction.RefreshMethodType.RefreshByIds,
RefresherId = msg.Refresher.UniqueIdentifier
}
};
}
return msg.Ids.Select(x => new RefreshInstruction
{
GuidId = (Guid)x,
RefreshType = RefreshInstruction.RefreshMethodType.RefreshById,
RefresherId = msg.Refresher.UniqueIdentifier
}).ToArray();
case MessageType.RefreshByJson:
return new[]
{
new RefreshInstruction
{
RefreshType = RefreshInstruction.RefreshMethodType.RefreshByJson,
RefresherId = msg.Refresher.UniqueIdentifier,
JsonPayload = msg.JsonPayload
}
};
case MessageType.RemoveById:
return msg.Ids.Select(x => new RefreshInstruction
{
IntId = (int)x,
RefreshType = RefreshInstruction.RefreshMethodType.RemoveById,
RefresherId = msg.Refresher.UniqueIdentifier
}).ToArray();
case MessageType.RefreshByInstance:
case MessageType.RemoveByInstance:
default:
throw new ArgumentOutOfRangeException();
}
}
private void SendMessages(IEnumerable<Message> messages)
{
var batchedMsg = new List<Tuple<Message, RefreshInstruction[]>>();
foreach (var msg in messages)
{
var instructions = ConvertToInstruction(msg);
batchedMsg.Add(new Tuple<Message, RefreshInstruction[]>(msg, instructions));
}
var servers = batchedMsg.SelectMany(x => x.Item1.Servers).Distinct();
try
{
//TODO: We should try to figure out the current server's address and if it matches any of the ones
// in the ServerAddress list, then just refresh directly on this server and exclude that server address
// from the list, this will save an internal request.
using (var cacheRefresher = new ServerSyncWebServiceClient())
{
var asyncResultsList = new List<IAsyncResult>();
LogStartDispatch();
// Go through each configured node submitting a request asynchronously
//NOTE: 'asynchronously' in this case does not mean that it will continue while we give the page back to the user!
foreach (var server in servers)
{
//set the server address
cacheRefresher.Url = server.ServerAddress;
var instructions = batchedMsg
.Where(x => x.Item1.Servers.Contains(server))
.SelectMany(x => x.Item2)
//only execute distinct instructions - no sense in running the same one.
.Distinct()
.ToArray();
asyncResultsList.Add(
cacheRefresher.BeginBulkRefresh(
instructions, Login, Password, null, null));
}
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
{
cacheRefresher.EndBulkRefresh(t);
}
catch (WebException ex)
{
LogDispatchNodeError(ex);
errorCount++;
}
catch (Exception ex)
{
LogDispatchNodeError(ex);
errorCount++;
}
}
LogDispatchBatchResult(errorCount);
}
}
catch (Exception ee)
{
LogDispatchBatchError(ee);
}
}
private void LogDispatchBatchError(Exception ee)
{
LogHelper.Error<BatchedServerMessenger>("Error refreshing distributed list", ee);
}
private void LogDispatchBatchResult(int errorCount)
{
LogHelper.Debug<BatchedServerMessenger>(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<BatchedServerMessenger>("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<BatchedServerMessenger>("Error refreshing a node in the distributed list, URI attempted: " + url, ex);
}
private void LogStartDispatch()
{
LogHelper.Info<BatchedServerMessenger>("Submitting calls to distributed servers");
}
}
}

View File

@@ -60,23 +60,6 @@ namespace Umbraco.Web.Cache
private static readonly DistributedCache InstanceObject = new DistributedCache();
///// <summary>
///// Fired when any cache refresher method has fired
///// </summary>
///// <remarks>
///// This could be used by developers to know when a cache refresher has executed on the local server.
///// Similarly to the content.AfterUpdateDocumentCache which fires locally on each machine.
///// </remarks>
//public event EventHandler<CacheUpdatedEventArgs> CacheChanged;
//private void OnCacheChanged(CacheUpdatedEventArgs args)
//{
// if (CacheChanged != null)
// {
// CacheChanged(this, args);
// }
//}
/// <summary>
/// Constructor
/// </summary>
@@ -109,6 +92,8 @@ namespace Umbraco.Web.Cache
/// </remarks>
public void Refresh<T>(Guid factoryGuid, Func<T, int> getNumericId, params T[] instances)
{
if (factoryGuid == Guid.Empty || instances.Length == 0 || getNumericId == null) return;
ServerMessengerResolver.Current.Messenger.PerformRefresh<T>(
ServerRegistrarResolver.Current.Registrar.Registrations,
GetRefresherById(factoryGuid),
@@ -124,6 +109,8 @@ namespace Umbraco.Web.Cache
/// <param name="id">The id of the node.</param>
public void Refresh(Guid factoryGuid, int id)
{
if (factoryGuid == Guid.Empty || id == default(int)) return;
ServerMessengerResolver.Current.Messenger.PerformRefresh(
ServerRegistrarResolver.Current.Registrar.Registrations,
GetRefresherById(factoryGuid),
@@ -138,6 +125,8 @@ namespace Umbraco.Web.Cache
/// <param name="id">The guid of the node.</param>
public void Refresh(Guid factoryGuid, Guid id)
{
if (factoryGuid == Guid.Empty || id == Guid.Empty) return;
ServerMessengerResolver.Current.Messenger.PerformRefresh(
ServerRegistrarResolver.Current.Registrar.Registrations,
GetRefresherById(factoryGuid),
@@ -152,6 +141,8 @@ namespace Umbraco.Web.Cache
/// <param name="jsonPayload"></param>
public void RefreshByJson(Guid factoryGuid, string jsonPayload)
{
if (factoryGuid == Guid.Empty || jsonPayload.IsNullOrWhiteSpace()) return;
ServerMessengerResolver.Current.Messenger.PerformRefresh(
ServerRegistrarResolver.Current.Registrar.Registrations,
GetRefresherById(factoryGuid),
@@ -165,6 +156,8 @@ namespace Umbraco.Web.Cache
/// <param name="factoryGuid">The unique identifier.</param>
public void RefreshAll(Guid factoryGuid)
{
if (factoryGuid == Guid.Empty) return;
RefreshAll(factoryGuid, true);
}
@@ -178,6 +171,8 @@ namespace Umbraco.Web.Cache
/// </param>
public void RefreshAll(Guid factoryGuid, bool allServers)
{
if (factoryGuid == Guid.Empty) return;
ServerMessengerResolver.Current.Messenger.PerformRefreshAll(
allServers
? ServerRegistrarResolver.Current.Registrar.Registrations
@@ -193,6 +188,8 @@ namespace Umbraco.Web.Cache
/// <param name="id">The id.</param>
public void Remove(Guid factoryGuid, int id)
{
if (factoryGuid == Guid.Empty || id == default(int)) return;
ServerMessengerResolver.Current.Messenger.PerformRemove(
ServerRegistrarResolver.Current.Registrar.Registrations,
GetRefresherById(factoryGuid),

View File

@@ -269,6 +269,7 @@
<Link>Properties\SolutionInfo.cs</Link>
</Compile>
<Compile Include="ApplicationContextExtensions.cs" />
<Compile Include="BatchedServerMessenger.cs" />
<Compile Include="CacheHelperExtensions.cs" />
<Compile Include="Cache\ApplicationCacheRefresher.cs" />
<Compile Include="Cache\ApplicationTreeCacheRefresher.cs" />

View File

@@ -26,7 +26,8 @@ namespace Umbraco.Web
// Request.RawUrl is still there
// response.Redirect does?! always remap to /vdir?!
public class UmbracoModule : IHttpModule
public class
UmbracoModule : IHttpModule
{
#region HttpModule event handlers
@@ -527,6 +528,8 @@ namespace Umbraco.Web
LogHelper.Debug<UmbracoModule>("Total milliseconds for umbraco request to process: " + DateTime.Now.Subtract(UmbracoContext.Current.ObjectCreated).TotalMilliseconds);
}
OnEndRequest(new EventArgs());
DisposeHttpContextItems(httpContext);
};
@@ -560,6 +563,13 @@ namespace Umbraco.Web
{
if (RouteAttempt != null)
RouteAttempt(this, args);
}
internal static event EventHandler<EventArgs> EndRequest;
private void OnEndRequest(EventArgs args)
{
if (EndRequest != null)
EndRequest(this, args);
}
#endregion
}

View File

@@ -275,7 +275,8 @@ namespace Umbraco.Web
DefaultRenderMvcControllerResolver.Current = new DefaultRenderMvcControllerResolver(typeof(RenderMvcController));
//Override the ServerMessengerResolver to set a username/password for the distributed calls
ServerMessengerResolver.Current.SetServerMessenger(new DefaultServerMessenger(() =>
//ServerMessengerResolver.Current.SetServerMessenger(new DefaultServerMessenger(() =>
ServerMessengerResolver.Current.SetServerMessenger(new BatchedServerMessenger(() =>
{
//we should not proceed to change this if the app/database is not configured since there will
// be no user, plus we don't need to have server messages sent if this is the case.

View File

@@ -4,55 +4,106 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Services;
using System.Xml;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Sync;
namespace umbraco.presentation.webservices
{
/// <summary>
/// Summary description for CacheRefresher.
/// </summary>
[WebService(Namespace="http://umbraco.org/webservices/")]
public class CacheRefresher : WebService
{
{
[WebMethod]
public void BulkRefresh(RefreshInstruction[] instructions, string login, string password)
{
if (BusinessLogic.User.validateCredentials(login, password) == false)
{
return;
}
//only execute distinct instructions - no sense in running the same one.
foreach (var instruction in instructions.Distinct())
{
switch (instruction.RefreshType)
{
case RefreshInstruction.RefreshMethodType.RefreshAll:
RefreshAll(instruction.RefresherId);
break;
case RefreshInstruction.RefreshMethodType.RefreshByGuid:
RefreshByGuid(instruction.RefresherId, instruction.GuidId);
break;
case RefreshInstruction.RefreshMethodType.RefreshById:
RefreshById(instruction.RefresherId, instruction.IntId);
break;
case RefreshInstruction.RefreshMethodType.RefreshByIds:
RefreshByIds(instruction.RefresherId, instruction.JsonIds);
break;
case RefreshInstruction.RefreshMethodType.RefreshByJson:
RefreshByJson(instruction.RefresherId, instruction.JsonPayload);
break;
case RefreshInstruction.RefreshMethodType.RemoveById:
RemoveById(instruction.RefresherId, instruction.IntId);
break;
}
}
}
[WebMethod]
public void RefreshAll(Guid uniqueIdentifier, string Login, string Password)
{
if (BusinessLogic.User.validateCredentials(Login, Password))
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
cr.RefreshAll();
RefreshAll(uniqueIdentifier);
}
}
[WebMethod]
private void RefreshAll(Guid uniqueIdentifier)
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
cr.RefreshAll();
}
[WebMethod]
public void RefreshByGuid(Guid uniqueIdentifier, Guid Id, string Login, string Password)
{
if (BusinessLogic.User.validateCredentials(Login, Password))
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
cr.Refresh(Id);
RefreshByGuid(uniqueIdentifier, Id);
}
}
private void RefreshByGuid(Guid uniqueIdentifier, Guid Id)
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
cr.Refresh(Id);
}
[WebMethod]
public void RefreshById(Guid uniqueIdentifier, int Id, string Login, string Password)
{
if (BusinessLogic.User.validateCredentials(Login, Password))
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
cr.Refresh(Id);
RefreshById(uniqueIdentifier, Id);
}
}
/// <summary>
private void RefreshById(Guid uniqueIdentifier, int Id)
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
cr.Refresh(Id);
}
/// <summary>
/// Refreshes objects for all Ids matched in the json string
/// </summary>
/// <param name="uniqueIdentifier"></param>
@@ -62,20 +113,25 @@ namespace umbraco.presentation.webservices
[WebMethod]
public void RefreshByIds(Guid uniqueIdentifier, string jsonIds, string Login, string Password)
{
var serializer = new JavaScriptSerializer();
var ids = serializer.Deserialize<int[]>(jsonIds);
if (BusinessLogic.User.validateCredentials(Login, Password))
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
foreach (var i in ids)
{
cr.Refresh(i);
}
RefreshByIds(uniqueIdentifier, jsonIds);
}
}
/// <summary>
private void RefreshByIds(Guid uniqueIdentifier, string jsonIds)
{
var serializer = new JavaScriptSerializer();
var ids = serializer.Deserialize<int[]>(jsonIds);
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
foreach (var i in ids)
{
cr.Refresh(i);
}
}
/// <summary>
/// Refreshes objects using the passed in Json payload, it will be up to the cache refreshers to deserialize
/// </summary>
/// <param name="uniqueIdentifier"></param>
@@ -90,25 +146,36 @@ namespace umbraco.presentation.webservices
{
if (BusinessLogic.User.validateCredentials(Login, Password))
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier) as IJsonCacheRefresher;
if (cr == null)
{
throw new InvalidOperationException("The cache refresher: " + uniqueIdentifier + " is not of type " + typeof (IJsonCacheRefresher));
}
cr.Refresh(jsonPayload);
RefreshByJson(uniqueIdentifier, jsonPayload);
}
}
[WebMethod]
public void RemoveById(Guid uniqueIdentifier, int Id, string Login, string Password) {
private void RefreshByJson(Guid uniqueIdentifier, string jsonPayload)
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier) as IJsonCacheRefresher;
if (cr == null)
{
throw new InvalidOperationException("The cache refresher: " + uniqueIdentifier + " is not of type " + typeof(IJsonCacheRefresher));
}
cr.Refresh(jsonPayload);
}
if (BusinessLogic.User.validateCredentials(Login, Password)) {
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
cr.Remove(Id);
[WebMethod]
public void RemoveById(Guid uniqueIdentifier, int Id, string Login, string Password)
{
if (BusinessLogic.User.validateCredentials(Login, Password))
{
RemoveById(uniqueIdentifier, Id);
}
}
[WebMethod]
private void RemoveById(Guid uniqueIdentifier, int Id)
{
var cr = CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
cr.Remove(Id);
}
[WebMethod]
public XmlDocument GetRefreshers(string Login, string Password)
{
if (BusinessLogic.User.validateCredentials(Login, Password))