/// <summary> /// Determine whether it can intercept the invocation /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual bool CanCache(_IInvocation invocation, IDictionary<string, object> invocationContext) { if (!Global.Cache.InterceptableCache.ContainsKey(invocation.Method)) { var possible = invocation.Method.ReturnType != typeof(void); if (!CanCacheNoneVirtualOrFinalMethods()) { //https://msdn.microsoft.com/en-us/library/system.reflection.methodbase.isvirtual(v=vs.110).aspx possible &= invocation.Method.IsVirtual && !invocation.Method.IsFinal; } if (possible && typeof(Task).IsAssignableFrom(invocation.Method.ReturnType) && invocation.Method.ReturnType.IsGenericType) { possible = invocation.Method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>); } if (possible) { var atts = Global.AttributeProvider.GetAttributes(invocation.Method, invocationContext); possible = !atts.Any(a => a is NoInterceptAttribute || a is NoCacheAttribute); } Global.Cache.InterceptableCache[invocation.Method] = possible; } return Global.Cache.InterceptableCache[invocation.Method]; }
/// <summary> /// Determine whether it can intercept the invocation /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual bool CanCache(_IInvocation invocation, IDictionary <string, object> invocationContext) { if (!Global.Cache.InterceptableCache.ContainsKey(invocation.Method)) { var possible = invocation.Method.ReturnType != typeof(void); if (!CanCacheNoneVirtualOrFinalMethods()) { //https://msdn.microsoft.com/en-us/library/system.reflection.methodbase.isvirtual(v=vs.110).aspx possible &= invocation.Method.IsVirtual && !invocation.Method.IsFinal; } if (possible && typeof(Task).IsAssignableFrom(invocation.Method.ReturnType) && invocation.Method.ReturnType.IsGenericType) { possible = invocation.Method.ReturnType.GetGenericTypeDefinition() == typeof(Task <>); } if (possible) { var atts = Global.AttributeProvider.GetAttributes(invocation.Method, invocationContext); possible = !atts.Any(a => a is NoInterceptAttribute || a is NoCacheAttribute); } Global.Cache.InterceptableCache[invocation.Method] = possible; } return(Global.Cache.InterceptableCache[invocation.Method]); }
/// <summary> /// Get <see cref="IAsyncCacheStore" /> for current invocation and context /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual IAsyncCacheStore GetAsyncCacheStore(_IInvocation invocation, IDictionary<string, object> invocationContext) { var att = invocationContext.TryGetByKey<ICacheSettings>(Global.__flatwhite_outputcache_attribute, OutputCacheAttribute.Default); if (att.CacheStoreId > 0) { var asyncCacheStore = Global.CacheStoreProvider.GetAsyncCacheStore(att.CacheStoreId); if (asyncCacheStore != null) return asyncCacheStore; } if (att.CacheStoreType != null && typeof(IAsyncCacheStore).IsAssignableFrom(att.CacheStoreType)) { try { return _activator.CreateInstance(att.CacheStoreType) as IAsyncCacheStore ?? Global.CacheStoreProvider.GetAsyncCacheStore(att.CacheStoreType); } catch (KeyNotFoundException) { } } if (att.CacheStoreType != null && typeof(ICacheStore).IsAssignableFrom(att.CacheStoreType)) { try { var syncCacheStore = _activator.CreateInstance(att.CacheStoreType) as ICacheStore ?? Global.CacheStoreProvider.GetCacheStore(att.CacheStoreType); if (syncCacheStore != null) return new CacheStoreAdaptor(syncCacheStore); } catch (KeyNotFoundException) { } } return Global.CacheStoreProvider.GetAsyncCacheStore(); }
public AutoResetEvent SetUp(string method) { var svc = Substitute.For<IUserService>(); svc.GetById(Arg.Any<Guid>()).Returns(cx => cx.Arg<Guid>()); svc.GetByIdAsync(Arg.Any<Guid>()).Returns(cx => Task.FromResult((object)cx.Arg<Guid>())); var builder = new ContainerBuilder().EnableFlatwhite(); builder .RegisterInstance(svc) .As<IUserService>() .EnableInterceptors(); var container = builder.Build(); var proxy = container.Resolve<IUserService>(); _invocation = Substitute.For<_IInvocation>(); _invocation.Arguments.Returns(new object[] { _id }); _invocation.Method.Returns(typeof(IUserService).GetMethod(method, BindingFlags.Instance | BindingFlags.Public)); _invocation.Proxy.Returns(proxy); Global.Cache = new MethodInfoCache(); var cacheStore = Substitute.For<ICacheStore>(); var autoResetEvent = new AutoResetEvent(false); cacheStore.When(x => x.Set(CacheInfo.CacheKey, Arg.Is<object>(obj => _id.Equals(((CacheItem)obj).Data)), Arg.Any<DateTimeOffset>())) .Do(c => autoResetEvent.Set()); cacheStore.StoreId.Returns(StoreId); Global.CacheStoreProvider.RegisterStore(cacheStore); return autoResetEvent; }
/// <summary> /// Resolve cache key /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual string GetCacheKey(_IInvocation invocation, IDictionary<string, object> invocationContext) { var info = invocationContext[Global.__flatwhite_outputcache_attribute] as ICacheSettings; if (info == null) { throw new InvalidOperationException($"{nameof(ICacheSettings)} object not found in {nameof(invocationContext)}"); } // The cache key must be different for different instance of same type var key = new StringBuilder($"Flatwhite::{(invocation.Method.DeclaringType ?? invocation.TargetType).FullName}.{invocation.Method.Name}("); var varyByParams = (info.VaryByParam ?? "").Split(new [] {',',' '}, StringSplitOptions.RemoveEmptyEntries); var varyByCustoms = info.GetAllVaryCustomKey().Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); var parameters = invocation.Method.GetParameters(); if (parameters.Length > 0) { BuildWithParams(invocation, parameters, varyByParams, key); key.Remove(key.Length - 2, 2); } key.Append(") :: "); if (varyByCustoms.Length > 0) { foreach (var custom in varyByCustoms) { BuildWithCustom("", invocationContext, custom, key); key.Append(", "); } } return key.ToString(); }
/// <summary> /// Resolve cache key /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual string GetCacheKey(_IInvocation invocation, IDictionary <string, object> invocationContext) { var info = invocationContext.TryGetByKey <ICacheSettings>(Global.__flatwhite_outputcache_attribute); if (info == null) { throw new InvalidOperationException($"{nameof(ICacheSettings)} object not found in {nameof(invocationContext)}"); } // The cache key must be different for different instance of same type var key = new StringBuilder($"Flatwhite::{(invocation.Method.DeclaringType ?? invocation.TargetType).FullName}.{invocation.Method.Name}("); var varyByParams = (info.VaryByParam ?? "").Split(new [] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); var varyByCustoms = info.GetAllVaryCustomKey().Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); var parameters = invocation.Method.GetParameters(); if (parameters.Length > 0) { BuildWithParams(invocation, parameters, varyByParams, key); key.Remove(key.Length - 2, 2); } key.Append(") :: "); if (varyByCustoms.Length > 0) { foreach (var custom in varyByCustoms) { BuildWithCustom("", invocationContext, custom, key); key.Append(", "); } } return(key.ToString().TrimEnd(' ', ':', ',')); }
private static void RefreshTheCache(WebApiCacheItem cacheItem, _IInvocation invocation, HttpRequestMessage request) { //Question: Should we create the phoenix only on the server that created it the first place? if (!Global.Cache.PhoenixFireCage.ContainsKey(cacheItem.Key)) { Global.Cache.PhoenixFireCage[cacheItem.Key] = new WebApiPhoenix(invocation, cacheItem, request); } Global.Cache.PhoenixFireCage[cacheItem.Key].Reborn(); }
private List <Attribute> GetInvocationMethodFilterAttributes(_IInvocation invocation, IDictionary <string, object> invocationContext) { var attributes = _attributeProvider.GetAttributes(invocation.Method, invocationContext).ToList(); if (invocation.Method != invocation.MethodInvocationTarget) { attributes.AddRange(_attributeProvider.GetAttributes(invocation.MethodInvocationTarget, invocationContext)); } return(attributes); }
private AutoResetEvent SetUp(string method, IUserService svc = null) { #if DEBUG if (Debugger.IsAttached) { _waitTime = int.MaxValue; } #endif Global.Init(); if (svc == null) { svc = Substitute.For <IUserService>(); if (method == nameof(IUserService.GetById)) { svc.GetById(Arg.Any <Guid>()).Returns(cx => cx.Arg <Guid>()); } if (method == nameof(IUserService.GetByIdAsync)) { svc.GetByIdAsync(Arg.Any <Guid>()).Returns(cx => Task.FromResult((object)cx.Arg <Guid>())); } } var builder = new ContainerBuilder(); builder.RegisterModule(new FlatwhiteCoreModule()); builder .RegisterInstance(svc) .As <IUserService>() .EnableInterceptors(); var container = builder.Build(); var proxy = container.Resolve <IUserService>(); _invocation = Substitute.For <_IInvocation>(); _invocation.Arguments.Returns(new object[] { _id }); _invocation.Method.Returns(typeof(IUserService).GetMethod(method, BindingFlags.Instance | BindingFlags.Public)); _invocation.Proxy.Returns(proxy); var cacheStore = Substitute.For <IAsyncCacheStore>(); var autoResetEvent = new AutoResetEvent(false); cacheStore.When(x => x.SetAsync(CacheInfo.Key, Arg.Is <object>(obj => _id.Equals(((CacheItem)obj).Data)), Arg.Any <DateTimeOffset>())) .Do(c => autoResetEvent.Set()); cacheStore.When(x => x.RemoveAsync(CacheInfo.Key)) .Do(c => autoResetEvent.Set()); cacheStore.StoreId.Returns(StoreId); Global.CacheStoreProvider.RegisterAsyncStore(cacheStore); return(autoResetEvent); }
private AutoResetEvent SetUp(string method, IUserService svc = null) { #if DEBUG if (Debugger.IsAttached) { _waitTime = int.MaxValue; } #endif Global.Init(); if (svc == null) { svc = Substitute.For<IUserService>(); if (method == nameof(IUserService.GetById)) { svc.GetById(Arg.Any<Guid>()).Returns(cx => cx.Arg<Guid>()); } if (method == nameof(IUserService.GetByIdAsync)) { svc.GetByIdAsync(Arg.Any<Guid>()).Returns(cx => Task.FromResult((object)cx.Arg<Guid>())); } } var builder = new ContainerBuilder(); builder.RegisterModule(new FlatwhiteCoreModule()); builder .RegisterInstance(svc) .As<IUserService>() .EnableInterceptors(); var container = builder.Build(); var proxy = container.Resolve<IUserService>(); _invocation = Substitute.For<_IInvocation>(); _invocation.Arguments.Returns(new object[] { _id }); _invocation.Method.Returns(typeof(IUserService).GetMethod(method, BindingFlags.Instance | BindingFlags.Public)); _invocation.Proxy.Returns(proxy); var cacheStore = Substitute.For<IAsyncCacheStore>(); var autoResetEvent = new AutoResetEvent(false); cacheStore.When(x => x.SetAsync(CacheInfo.Key, Arg.Is<object>(obj => _id.Equals(((CacheItem)obj).Data)), Arg.Any<DateTimeOffset>())) .Do(c => autoResetEvent.Set()); cacheStore.When(x => x.RemoveAsync(CacheInfo.Key)) .Do(c => autoResetEvent.Set()); cacheStore.StoreId.Returns(StoreId); Global.CacheStoreProvider.RegisterAsyncStore(cacheStore); return autoResetEvent; }
private void DisposeOldPhoenixAndCreateNew(_IInvocation invocation, WebApiCacheItem cacheItem, HttpRequestMessage request) { //Question: Should we do it only on the box that created the phoenix the first place? Phoenix phoenix; if (Global.Cache.PhoenixFireCage.TryGetValue(cacheItem.Key, out phoenix)) { phoenix?.Dispose(); } Global.Cache.PhoenixFireCage[cacheItem.Key] = new WebApiPhoenix(invocation, cacheItem, request); }
/// <summary> /// Create the phoenix object which can refresh the cache itself if StaleWhileRevalidate > 0 /// </summary> /// <param name="invocation"></param> /// <param name="cacheItem"></param> /// <param name="request"></param> /// <returns></returns> private void CreatePhoenix(_IInvocation invocation, WebApiCacheItem cacheItem, HttpRequestMessage request) { if (cacheItem.StaleWhileRevalidate <= 0 || request.Method != HttpMethod.Get) { return; } if (Global.Cache.PhoenixFireCage.ContainsKey(cacheItem.Key)) { Global.Cache.PhoenixFireCage[cacheItem.Key].Dispose(); } Global.Cache.PhoenixFireCage[cacheItem.Key] = new WebApiPhoenix(invocation, cacheItem, request); }
/// <summary> /// Create the phoenix object which can refresh the cache itself if StaleWhileRevalidate > 0 /// and store by key in Global.Cache.Phoenix /// </summary> /// <param name="invocation"></param> /// <param name="cacheItem"></param> /// <returns></returns> private void CreatePhoenix(_IInvocation invocation, CacheItem cacheItem) { if (cacheItem.StaleWhileRevalidate <= 0) { return; } if (Global.Cache.PhoenixFireCage.ContainsKey(cacheItem.Key)) { Global.Cache.PhoenixFireCage[cacheItem.Key].Dispose(); } Global.Cache.PhoenixFireCage[cacheItem.Key] = new Phoenix(invocation, cacheItem); }
/// <summary> /// Get empty list change monitor /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual IEnumerable <IChangeMonitor> GetChangeMonitors(_IInvocation invocation, IDictionary <string, object> invocationContext) { var att = invocationContext.TryGetByKey <ICacheSettings>(Global.__flatwhite_outputcache_attribute, OutputCacheAttribute.Default); if (string.IsNullOrWhiteSpace(att?.RevalidateKeyFormat)) { yield break; } var revalidationKey = CacheKeyProvider.GetRevalidateKey(invocation, att.RevalidateKeyFormat); yield return(new FlatwhiteCacheEntryChangeMonitor(revalidationKey)); }
/// <summary> /// Build the key with provided varyByParams /// </summary> /// <param name="invocation"></param> /// <param name="parameters"></param> /// <param name="varyByParams"></param> /// <param name="key"></param> protected virtual void BuildWithParams(_IInvocation invocation, ParameterInfo[] parameters, string[] varyByParams, StringBuilder key) { for (var i = 0; i < parameters.Length; i++) { var argKey = "*"; if (varyByParams.Contains("*") || varyByParams.Contains(parameters[i].Name)) { var arg = invocation.GetArgumentValue(i); argKey = _hashCodeGeneratorProvider.GetForType(parameters[i].ParameterType).GetCode(arg); } key.Append($"{parameters[i].ParameterType.Name}:{argKey}, "); } }
/// <summary> /// Get <see cref="IAsyncCacheStore" /> for current invocation and context /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual IAsyncCacheStore GetAsyncCacheStore(_IInvocation invocation, IDictionary <string, object> invocationContext) { var att = invocationContext.TryGetByKey <ICacheSettings>(Global.__flatwhite_outputcache_attribute, OutputCacheAttribute.Default); if (att.CacheStoreId > 0) { try { var asyncCacheStore = Global.CacheStoreProvider.GetAsyncCacheStore(att.CacheStoreId); if (asyncCacheStore != null) { return(asyncCacheStore); } } catch (Exception ex) { Global.Logger.Error($"Cannot resolve cache store with id {att.CacheStoreId}", ex); } } if (att.CacheStoreType != null && typeof(IAsyncCacheStore).IsAssignableFrom(att.CacheStoreType)) { try { var asyncCacheStore = Global.CacheStoreProvider.GetAsyncCacheStore(att.CacheStoreType); if (asyncCacheStore != null) { return(asyncCacheStore); } } catch (KeyNotFoundException) { } } if (att.CacheStoreType != null && typeof(ICacheStore).IsAssignableFrom(att.CacheStoreType)) { try { var syncCacheStore = Global.CacheStoreProvider.GetCacheStore(att.CacheStoreType); if (syncCacheStore != null) { return(new CacheStoreAdaptor(syncCacheStore)); } } catch (KeyNotFoundException) { } } return(Global.CacheStoreProvider.GetAsyncCacheStore()); }
/// <summary> /// Initialize a phoenix with provided cacheDuration and staleWhileRevalidate values /// </summary> /// <param name="invocation"></param> /// <param name="info"></param> public Phoenix(_IInvocation invocation, CacheInfo info) { _info = info; _phoenixState = _info.StaleWhileRevalidate > 0 ? (IPhoenixState)new RaisingPhoenix() : new DisposingPhoenix(Die); if (invocation.Proxy != null) { // It is really a dynamic proxy _instanceTargetField = invocation.Proxy.GetType().GetField("__target", BindingFlags.Public | BindingFlags.Instance); } Arguments = invocation.Arguments; MethodInfo = invocation.Method; _timer = new Timer(_ => Reborn(), null, _info.GetRefreshTime(), TimeSpan.Zero); }
/// <summary> /// Get change monitors /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public override IEnumerable <IChangeMonitor> GetChangeMonitors(_IInvocation invocation, IDictionary <string, object> invocationContext) { var monitors = base.GetChangeMonitors(invocation, invocationContext).ToList(); foreach (var e in _expressions) { var m = ExpressionHelper.ToMethodInfo(e.Expression); if (m == invocation.Method) { monitors.AddRange(e.ChangeMonitorFactory(invocation, invocationContext)); break; } } return(monitors); }
/// <summary> /// Get <see cref="ICacheStrategy" /> from <see cref="IDependencyScope" /> /// </summary> /// <param name="scope"></param> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> protected virtual ICacheStrategy GetCacheStrategy(IDependencyScope scope, _IInvocation invocation, IDictionary <string, object> invocationContext) { var strategy = CacheStrategyType != null?scope.GetService(CacheStrategyType) as ICacheStrategy : null; if (strategy == null) { var strategyProvider = scope.GetService(typeof(ICacheStrategyProvider)) as ICacheStrategyProvider ?? Global.CacheStrategyProvider; strategy = strategyProvider.GetStrategy(invocation, invocationContext); } if (strategy == null) { throw new Exception("Cannot find caching strategy for this request"); } return(strategy); }
/// <summary> /// Initialize a phoenix with provided cacheDuration and staleWhileRevalidate values /// </summary> /// <param name="invocation"></param> /// <param name="info"></param> public Phoenix(_IInvocation invocation, CacheItem info) { _info = info.CloneWithoutData(); _phoenixState = _info.StaleWhileRevalidate > 0 ? (IPhoenixState) new InActivePhoenix() : new DisposingPhoenix(DieAsync()); if (invocation.Proxy != null) { // It is really a dynamic proxy _instanceTargetField = invocation.Proxy.GetType().GetField("__target", BindingFlags.Public | BindingFlags.Instance); } Arguments = invocation.Arguments; MethodInfo = invocation.Method; _timer = new Timer(_ => Reborn(), null, _info.GetRefreshTime(), TimeSpan.Zero); }
/// <summary> /// Create the phoenix object which can refresh the cache itself if StaleWhileRevalidate > 0 /// and store by key in Global.Cache.Phoenix /// </summary> /// <param name="invocation"></param> /// <param name="cacheItem"></param> /// <returns></returns> private void CreatePhoenix(_IInvocation invocation, CacheItem cacheItem) { if (cacheItem.StaleWhileRevalidate <= 0) { return; } Phoenix phoenix; if (Global.Cache.PhoenixFireCage.TryGetValue(cacheItem.Key, out phoenix)) { phoenix?.Dispose(); } Global.Cache.PhoenixFireCage[cacheItem.Key] = new Phoenix(invocation, cacheItem); }
/// <summary> /// Create the phoenix object which can refresh the cache itself if StaleWhileRevalidate > 0 /// </summary> /// <param name="invocation"></param> /// <param name="cacheItem"></param> /// <param name="request"></param> /// <returns></returns> private void CreatePhoenix(_IInvocation invocation, WebApiCacheItem cacheItem, HttpRequestMessage request) { if (cacheItem.StaleWhileRevalidate <= 0 || request.Method != HttpMethod.Get) { return; } Phoenix phoenix; if (Global.Cache.PhoenixFireCage.TryGetValue(cacheItem.Key, out phoenix)) { phoenix?.Dispose(); } Global.Cache.PhoenixFireCage[cacheItem.Key] = new WebApiPhoenix(invocation, cacheItem, request); }
/// <summary> /// Intercept the invocation /// </summary> /// <param name="invocation"></param> public void Intercept(_IInvocation invocation) { if (!invocation.Method.IsVirtual || invocation.Method.IsFinal) { invocation.Proceed(); return; } var methodExecutingContext = new MethodExecutingContext { InvocationContext = _contextProvider.GetContext(), MethodInfo = invocation.Method, Invocation = invocation }; var attributes = GetInvocationMethodFilterAttributes(invocation, methodExecutingContext.InvocationContext); if (attributes.Any(a => a is NoInterceptAttribute)) { invocation.Proceed(); return; } var filterAttributes = attributes.OfType <MethodFilterAttribute>().OrderBy(x => x.Order).ToList(); var isAsync = typeof(Task).IsAssignableFrom(invocation.Method.ReturnType); if (isAsync) { if (invocation.Method.ReturnType.IsGenericType && invocation.Method.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)) { var taskResultType = invocation.Method.ReturnType.GetGenericArguments()[0]; var mInfo = _handleAsyncWithTypeMethod.MakeGenericMethod(taskResultType); filterAttributes.Add(new InvocationAttribute(invocation, taskResultType)); invocation.ReturnValue = mInfo.Invoke(this, new object[] { filterAttributes, methodExecutingContext, taskResultType }); } else { filterAttributes.Add(new InvocationAttribute(invocation)); invocation.ReturnValue = HandleAsync(filterAttributes, methodExecutingContext); } } else { filterAttributes.Add(new InvocationAttribute(invocation)); HandleSync(filterAttributes, methodExecutingContext); } }
/// <summary> /// Initialize a phoenix with provided cacheDuration and staleWhileRevalidate values /// </summary> /// <param name="invocation"></param> /// <param name="info"></param> public Phoenix(_IInvocation invocation, CacheItem info) { _id = Guid.NewGuid().ToString("N"); _info = info.CloneWithoutData(); _phoenixState = _info.StaleWhileRevalidate > 0 ? (IPhoenixState) new InActivePhoenix() : new DisposingPhoenix(DieAsync()); if (invocation.Proxy != null) { // It is really a dynamic proxy _instanceTargetField = invocation.Proxy.GetType().GetField("__target", BindingFlags.Public | BindingFlags.Instance); } Arguments = invocation.Arguments; MethodInfo = invocation.Method; _allPhoenix[_id] = this; //NOTE: Memory leak: http://www.codeproject.com/Questions/185734/Threading-Timer-prevents-GC-collection _timer = new Timer(RebornCallback, _id, _info.GetRefreshTime(), TimeSpan.Zero); }
/// <summary> /// Get <see cref="ICacheStore" /> for current invocation and context /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual ICacheStore GetCacheStore(_IInvocation invocation, IDictionary<string, object> invocationContext) { var att = invocationContext.TryGetByKey<ICacheSettings>(Global.__flatwhite_outputcache_attribute, OutputCacheAttribute.Default); ICacheStore cacheStore = null; try { if (att.CacheStoreId > 0) { cacheStore = Global.CacheStoreProvider.GetCacheStore(att.CacheStoreId); } if (cacheStore == null && att.CacheStoreType != null && typeof (ICacheStore).IsAssignableFrom(att.CacheStoreType)) { cacheStore = Global.CacheStoreProvider.GetCacheStore(att.CacheStoreType); } } catch (KeyNotFoundException) { } return cacheStore ?? Global.CacheStoreProvider.GetCacheStore(); }
/// <summary> /// Build the revalidation key from provided keyFormat /// </summary> /// <param name="invocation"></param> /// <param name="keyFormat"></param> /// <returns></returns> public virtual string GetRevalidateKey(_IInvocation invocation, string keyFormat) { var parameters = invocation.Method.GetParameters().ToList(); var placeholders = Regex.Matches(keyFormat, "{(?<Argument>[\\w\\d_]+)}", RegexOptions.Compiled | RegexOptions.Singleline); var key = new StringBuilder(keyFormat); for (var i = 0; i < placeholders.Count; i++) { var match = placeholders[i].Groups["Argument"].Value; var index = parameters.FindIndex(p => p.Name == match); if (index >= 0) { var arg = invocation.GetArgumentValue(index); var argKey = _hashCodeGeneratorProvider.GetForType(parameters[index].ParameterType).GetCode(arg); key = key.Replace($"{{{match}}}", argKey); } } return(key.ToString()); }
/// <summary> /// Get <see cref="ICacheStore" /> for current invocation and context /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual ICacheStore GetCacheStore(_IInvocation invocation, IDictionary <string, object> invocationContext) { var att = invocationContext.TryGetByKey <ICacheSettings>(Global.__flatwhite_outputcache_attribute, OutputCacheAttribute.Default); ICacheStore cacheStore = null; try { if (att.CacheStoreId > 0) { cacheStore = Global.CacheStoreProvider.GetCacheStore(att.CacheStoreId); } if (cacheStore == null && att.CacheStoreType != null && typeof(ICacheStore).IsAssignableFrom(att.CacheStoreType)) { cacheStore = Global.CacheStoreProvider.GetCacheStore(att.CacheStoreType); } } catch (KeyNotFoundException) { } return(cacheStore ?? Global.CacheStoreProvider.GetCacheStore()); }
/// <summary> /// Initializes a WebApiPhoenix /// </summary> /// <param name="invocation"></param> /// <param name="cacheItem">This should the the WebApiCacheItem instance</param> /// <param name="requestMessage"></param> public WebApiPhoenix(_IInvocation invocation, WebApiCacheItem cacheItem, HttpRequestMessage requestMessage) : base(invocation, cacheItem) { _cacheItem = cacheItem; _clonedRequestMessage = new HttpRequestMessage { RequestUri = requestMessage.RequestUri, Method = requestMessage.Method, Version = requestMessage.Version }; if (!string.IsNullOrWhiteSpace(WebApiExtensions._fwConfig.LoopbackAddress)) { _clonedRequestMessage.RequestUri = new Uri($"{WebApiExtensions._fwConfig.LoopbackAddress}{_clonedRequestMessage.RequestUri.PathAndQuery}"); } _clonedRequestMessage.Content = null; foreach (var h in requestMessage.Headers) { _clonedRequestMessage.Headers.Add(h.Key, h.Value); } _clonedRequestMessage.Headers.CacheControl = requestMessage.Headers.CacheControl ?? new CacheControlHeaderValue(); }
public ICacheStrategy GetCacheStrategyPublic(IDependencyScope scope, _IInvocation invocation, IDictionary<string, object> invocationContext) { return GetCacheStrategy(scope, invocation, invocationContext); }
/// <summary> /// Return a <see cref="ICacheStrategy" /> if the request is webApi request /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public ICacheStrategy GetStrategy(_IInvocation invocation, IDictionary<string, object> invocationContext) { return invocationContext.ContainsKey(WebApiExtensions.__webApi) ? new WebApiCacheStrategy() : new DefaultCacheStrategy(); }
public void CreatePhoenixPublic(_IInvocation invocation, WebApiCacheItem cacheItem, HttpRequestMessage request) { var methodInfo = typeof(Flatwhite.WebApi.OutputCacheAttribute).GetMethod("CreatePhoenix", BindingFlags.Instance | BindingFlags.NonPublic); methodInfo.Invoke(this, new object[] { invocation, cacheItem, request }); }
/// <summary> /// Build the key with provided varyByCustoms /// </summary> /// <param name="invocation"></param> /// <param name="parameters"></param> /// <param name="varyByParams"></param> /// <param name="key"></param> protected virtual void BuildWithParams(_IInvocation invocation, ParameterInfo[] parameters, string[] varyByParams, StringBuilder key) { for (var i = 0; i < parameters.Length; i++) { var arg = invocation.GetArgumentValue(i); var argKey = "*"; if (varyByParams.Contains("*") || varyByParams.Contains(parameters[i].Name)) { argKey = _hashCodeGeneratorProvider.GetForType(parameters[i].ParameterType).GetCode(arg); } key.Append($"{parameters[i].ParameterType.Name}:{argKey}, "); } }
public ICacheStrategy GetStrategy(_IInvocation invocation, IDictionary<string, object> invocationContext) { return new DefaultCacheStrategy(); }
public ICacheStrategy GetStrategy(_IInvocation invocation, IDictionary <string, object> invocationContext) { return(new DefaultCacheStrategy()); }
public WebApiPhoenixWithPublicMethods(_IInvocation invocation, WebApiCacheItem cacheItem, HttpRequestMessage originalRequestMessage) : base(invocation, cacheItem, originalRequestMessage) { }
/// <summary> /// WebAPI should use AsyncCacheStore instead /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public override ICacheStore GetCacheStore(_IInvocation invocation, IDictionary <string, object> invocationContext) { throw new System.NotSupportedException(); }
public InvocationAttribute(_IInvocation invocation, Type taskGenericReturnType = null) { _invocation = invocation; _taskGenericReturnType = taskGenericReturnType; }
/// <summary> /// Get <see cref="ICacheStrategy" /> from <see cref="IDependencyScope" /> if <see cref="CacheStrategyType"/> has value /// <para>Otherwise resolve from <see cref="Global.CacheStrategyProvider"/></para> /// </summary> /// <param name="request"></param> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> protected virtual ICacheStrategy GetCacheStrategy(HttpRequestMessage request, _IInvocation invocation, IDictionary <string, object> invocationContext) { ICacheStrategy strategy = null; if (CacheStrategyType != null) { strategy = request.GetDependencyScope().GetService(CacheStrategyType) as ICacheStrategy; if (strategy?.GetType() != CacheStrategyType) { throw new Exception($"Cannot find cache strategy type {CacheStrategyType.Name} from dependecy scope of this request {request.RequestUri.PathAndQuery}"); } } if (strategy == null) { strategy = Global.CacheStrategyProvider.GetStrategy(invocation, invocationContext); } if (strategy == null) { throw new Exception($"Cannot find cache strategy from Global.CacheStrategyProvider of this request {request.RequestUri.PathAndQuery}"); } return(strategy); }
/// <summary> /// Get <see cref="ICacheStrategy" /> from <see cref="IDependencyScope" /> /// </summary> /// <param name="scope"></param> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> protected virtual ICacheStrategy GetCacheStrategy(IDependencyScope scope, _IInvocation invocation, IDictionary<string, object> invocationContext) { var strategy = CacheStrategyType != null ? scope.GetService(CacheStrategyType) as ICacheStrategy : null; if (strategy == null) { var strategyProvider = scope.GetService(typeof (ICacheStrategyProvider)) as ICacheStrategyProvider ?? Global.CacheStrategyProvider; strategy = strategyProvider.GetStrategy(invocation, invocationContext); } if (strategy == null) throw new Exception("Cannot find caching strategy for this request"); return strategy; }
/// <summary> /// Get empty list change monitor /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual IEnumerable<IChangeMonitor> GetChangeMonitors(_IInvocation invocation, IDictionary<string, object> invocationContext) { var att = invocationContext.TryGetByKey<ICacheSettings>(Global.__flatwhite_outputcache_attribute, OutputCacheAttribute.Default); if (string.IsNullOrWhiteSpace(att?.RevalidateKeyFormat)) { yield break; } var revalidationKey = CacheKeyProvider.GetRevalidateKey(invocation, att.RevalidateKeyFormat); yield return new FlatwhiteCacheEntryChangeMonitor(revalidationKey); }
/// <summary> /// Create the phoenix object which can refresh the cache itself if StaleWhileRevalidate > 0 /// </summary> /// <param name="invocation"></param> /// <param name="cacheItem"></param> /// <param name="request"></param> /// <param name="mediaTypeFormatter">The formater that was used to create the reasponse at the first invocation</param> /// <returns></returns> private void CreatePhoenix(_IInvocation invocation, WebApiCacheItem cacheItem, HttpRequestMessage request, MediaTypeFormatter mediaTypeFormatter) { var cacheInfo = new CacheInfo { CacheKey = cacheItem.Key, CacheStoreId = cacheItem.StoreId, CacheDuration = MaxAge, StaleWhileRevalidate = StaleWhileRevalidate, AutoRefresh = AutoRefresh }; var phoenix = new WebApiPhoenix(invocation, cacheInfo, cacheItem, request, mediaTypeFormatter); if (Global.Cache.PhoenixFireCage.ContainsKey(cacheItem.Key)) { Global.Cache.PhoenixFireCage[cacheItem.Key].Dispose(); } Global.Cache.PhoenixFireCage[cacheItem.Key] = phoenix; }
public ICacheStrategy GetCacheStrategyPublic(HttpRequestMessage request, _IInvocation invocation, IDictionary <string, object> invocationContext) { return(GetCacheStrategy(request, invocation, invocationContext)); }
/// <summary> /// Get <see cref="IAsyncCacheStore" /> for current invocation and context /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public virtual IAsyncCacheStore GetAsyncCacheStore(_IInvocation invocation, IDictionary<string, object> invocationContext) { var att = invocationContext.TryGetByKey<ICacheSettings>(Global.__flatwhite_outputcache_attribute, OutputCacheAttribute.Default); if (att.CacheStoreId > 0) { try { var asyncCacheStore = Global.CacheStoreProvider.GetAsyncCacheStore(att.CacheStoreId); if (asyncCacheStore != null) return asyncCacheStore; } catch (Exception ex) { Global.Logger.Error($"Cannot resolve cache store with id {att.CacheStoreId}", ex); } } if (att.CacheStoreType != null && typeof(IAsyncCacheStore).IsAssignableFrom(att.CacheStoreType)) { try { var asyncCacheStore = Global.CacheStoreProvider.GetAsyncCacheStore(att.CacheStoreType); if (asyncCacheStore != null) return asyncCacheStore; } catch (KeyNotFoundException) { } } if (att.CacheStoreType != null && typeof(ICacheStore).IsAssignableFrom(att.CacheStoreType)) { try { var syncCacheStore = Global.CacheStoreProvider.GetCacheStore(att.CacheStoreType); if (syncCacheStore != null) return new CacheStoreAdaptor(syncCacheStore); } catch (KeyNotFoundException) { } } return Global.CacheStoreProvider.GetAsyncCacheStore(); }
public void CreatePhoenixPublic(_IInvocation invocation, CacheItem cacheItem) { var methodInfo = typeof(OutputCacheAttribute).GetMethod("CreatePhoenix", BindingFlags.Instance | BindingFlags.NonPublic); methodInfo.Invoke(this, new object[] { invocation, cacheItem }); }
/// <summary> /// Build the revalidation key from provided keyFormat /// </summary> /// <param name="invocation"></param> /// <param name="keyFormat"></param> /// <returns></returns> public virtual string GetRevalidateKey(_IInvocation invocation, string keyFormat) { var parameters = invocation.Method.GetParameters().ToList(); var placeholders = Regex.Matches(keyFormat, "{(?<Argument>[\\w\\d_]+)}", RegexOptions.Compiled | RegexOptions.Singleline); var key = new StringBuilder(keyFormat); for (var i = 0; i < placeholders.Count; i++) { var match = placeholders[i].Groups["Argument"].Value; var index = parameters.FindIndex(p => p.Name == match); if (index >= 0) { var arg = invocation.GetArgumentValue(index); var argKey = _hashCodeGeneratorProvider.GetForType(parameters[index].ParameterType).GetCode(arg); key = key.Replace($"{{{match}}}", argKey); } } return key.ToString(); }
/// <summary> /// Create the phoenix object which can refresh the cache itself if StaleWhileRevalidate > 0 /// and store by key in Global.Cache.Phoenix /// </summary> /// <param name="invocation"></param> /// <param name="cacheItem"></param> /// <returns></returns> private void CreatePhoenix(_IInvocation invocation, CacheItem cacheItem) { var cacheInfo = new CacheInfo { CacheKey = cacheItem.Key, CacheStoreId = cacheItem.StoreId, CacheDuration = Duration, StaleWhileRevalidate = StaleWhileRevalidate, AutoRefresh = AutoRefresh }; if (Global.Cache.PhoenixFireCage.ContainsKey(cacheItem.Key)) { Global.Cache.PhoenixFireCage[cacheItem.Key].Dispose(); } Global.Cache.PhoenixFireCage[cacheItem.Key] = new Phoenix(invocation, cacheInfo); ; }
public ICacheStrategy GetCacheStrategyPublic(IDependencyScope scope, _IInvocation invocation, IDictionary <string, object> invocationContext) { return(GetCacheStrategy(scope, invocation, invocationContext)); }
/// <summary> /// WebAPI should use AsyncCacheStore instead /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public override ICacheStore GetCacheStore(_IInvocation invocation, IDictionary<string, object> invocationContext) { throw new System.NotSupportedException(); }
/// <summary> /// Return a <see cref="ICacheStrategy" /> if the request is webApi request /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public ICacheStrategy GetStrategy(_IInvocation invocation, IDictionary<string, object> invocationContext) { return invocationContext.ContainsKey(WebApiExtensions.__webApi) ? new WebApiCacheStrategy(new WebApiDependencyResolverActivator(() => invocationContext[WebApiExtensions.__webApi_dependency_scope] as IDependencyScope)) : new DefaultCacheStrategy(); }
public WebApiPhoenixWithPublicMethods(_IInvocation invocation, WebApiCacheItem cacheItem, HttpRequestMessage requestMessage) : base(invocation, cacheItem, requestMessage) { }
/// <summary> /// Return a <see cref="ICacheStrategy" /> if the request is webApi request /// </summary> /// <param name="invocation"></param> /// <param name="invocationContext"></param> /// <returns></returns> public ICacheStrategy GetStrategy(_IInvocation invocation, IDictionary <string, object> invocationContext) { return(invocationContext.ContainsKey(WebApiExtensions.__webApi) ? new WebApiCacheStrategy() : new DefaultCacheStrategy()); }
/// <summary> /// Initializes a WebApiPhoenix /// </summary> /// <param name="invocation"></param> /// <param name="cacheItem">This should the the WebApiCacheItem instance</param> /// <param name="originalRequestMessage"></param> public WebApiPhoenix(_IInvocation invocation, WebApiCacheItem cacheItem, HttpRequestMessage originalRequestMessage) : base(invocation, cacheItem) { _cacheItem = cacheItem; _originalRequestMessage = originalRequestMessage; }