public void Init(IDbContextBase context, IQueryable query, CacheInfo cacheInfo) { CacheInfo = cacheInfo; using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = cacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Message = $"CacheSql Dependency {cacheInfo.Name} before init at {DateTime.Now.ToString()} ..."; trace.Data["State"] = "initialize"; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } Init(context, query, 500, cacheInfo); using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = cacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Message = $"CacheSql Dependency {cacheInfo.Name} was initilized at {DateTime.Now.ToString()} ..."; trace.Data["State"] = "initialize"; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } }
private void DependencyOnChange(object sender, SqlNotificationEventArgs e) { // Move the original SqlDependency event handler. if (e.Type == SqlNotificationType.Subscribe || e.Info == SqlNotificationInfo.Error) { using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = CacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Message = $"CacheSql Dependency {CacheInfo.Name} has faced with an Error at {DateTime.Now.ToString()} ..."; trace.Data["State"] = "Error"; trace.Data["Type"] = e.Type.ToString(); trace.Data["Info"] = e.Info.ToString(); Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } Core.Cmn.AppBase.LogService.Write($"Some thing is wrong on SqlDependency Change, the query is {iquery} and SqlNotificationInfo is {e.Info} and Source is {e.Source}..."); } dependency.OnChange -= DependencyOnChange; if (OnChanged != null) { try { OnChanged(this, e); } catch (Exception ex) { using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = CacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Message = $"CacheSql Dependency {CacheInfo.Name} has faced with an exception at {DateTime.Now.ToString()} ..."; trace.Data["State"] = "Error"; trace.Data["Exception"] = ex.ToString(); trace.Data["Type"] = e.Type.ToString(); trace.Data["Info"] = e.Info.ToString(); Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } Core.Cmn.AppBase.LogService.Handle(ex, $"Exception on executing cache on SqlDependency Change, the query is {iquery}..."); } } // We re-register the SqlDependency. // RegisterSqlDependency(); }
private static void ExcecuteQueryForRefreshingSqlDependencyCache(CacheInfo currentCacheInfo, Type returnCacheType, object queryableCacheExecution, int delay) { try { using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = currentCacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Data["State"] = "ExcecuteQuery"; trace.Message = $"CacheSql Dependency {currentCacheInfo.Name} before ExcecuteQuery at {DateTime.Now.ToString()} ..."; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } (typeof(CacheBase)).GetMethod("RefreshCache").MakeGenericMethod(returnCacheType).Invoke(null, new object[] { queryableCacheExecution, currentCacheInfo }); using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = currentCacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Data["State"] = "ExcecuteQuery"; trace.Message = $"CacheSql Dependency {currentCacheInfo.Name} after ExcecuteQuery at {DateTime.Now.ToString()} ..."; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } } catch (Exception ex) { using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = currentCacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Data["State"] = "ExcecuteQuery"; trace.Message = $"CacheSql Dependency {currentCacheInfo.Name} on ExcecuteQuery has faced with an exception at {DateTime.Now.ToString()} ..."; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } Task.Delay(delay).Wait(); ((IQueryableCacheDataProvider)queryableCacheExecution).DbContext = AppBase.DependencyInjectionFactory.CreateContextInstance(); try { AppBase.LogService.Handle(ex, $"Exception on excecuting Query for refreshing a DependencySql Cache on {currentCacheInfo.Name}"); } catch { } ExcecuteQueryForRefreshingSqlDependencyCache(currentCacheInfo, returnCacheType, queryableCacheExecution, delay + 1000); } }
private void Init(IDbContextBase context, IQueryable query, int delayForRetryOnError, CacheInfo cacheInfo) { try { StartMonitor(context); this.iquery = query; // Get the ObjectQuery directly or convert the DbQuery to ObjectQuery. Core.Cmn.Extensions.QueryableExt.GetSqlCommand <TEntity>(context, query, ref connection, ref command); RegisterSqlDependency(); } catch (Exception ex) { try { using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = cacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Data["Exception"] = ex.ToString(); trace.Message = $"CacheSql Dependency {cacheInfo.Name} has faced with an exception at {DateTime.Now.ToString()} ..."; trace.Data["State"] = "initialize"; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } Core.Cmn.AppBase.LogService.Handle(ex, $"Exception on initialize ImmediateNotificationRegister for cache on SqlDependency, the query is {iquery}..."); } catch { } Task.Delay(delayForRetryOnError).Wait(); Init(context, query, delayForRetryOnError + 1000, cacheInfo); } }
private static void BuildCachesInAssembly(Type dBContext, Assembly repAssembly, bool isRepositoryAssembly) { IEnumerable <MethodInfo> types = null; try { types = repAssembly.GetTypes() .SelectMany(type => type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); } catch { //This exception is don't care. return; } foreach (var type in types) { var cacheInfoAtt = type.GetAttributeValue <CacheableAttribute, CacheableAttribute>(cAtt => cAtt); if (cacheInfoAtt != null) { //if (string.IsNullOrEmpty(cacheInfo.Key)) //{ // throw new ArgumentNullException("Cache Key can't be empty."); //} if ((type as MethodInfo).IsStatic) { if (!(type as MethodInfo).IsGenericMethod) { var methodInfo = type as MethodInfo; var parames = methodInfo.GetParameters(); Type funcBaseType = null; if (parames.Count() == 0) { funcBaseType = typeof(Func <>); } if (parames.Count() == 1) { funcBaseType = typeof(Func <,>); } if (parames.Count() == 2) { funcBaseType = typeof(Func <, ,>); } if (parames.Count() == 3) { funcBaseType = typeof(Func <, , ,>); } if (parames.Count() == 4) { funcBaseType = typeof(Func <, , , ,>); } if (parames.Count() == 5) { funcBaseType = typeof(Func <, , , , ,>); } List <Type> tArgs = methodInfo.GetParameters().Select(item => item.ParameterType).ToList(); tArgs.Add(methodInfo.ReturnType); var funcType = funcBaseType.MakeGenericType(tArgs.ToArray()); var funcInstanc = methodInfo.CreateDelegate(funcType); var key = funcInstanc.Method.GetHashCode().ToString(); CacheInfo currentCacheInfo = null; if (!CacheInfoDic.TryGetValue(key, out currentCacheInfo)) { // throw new ArgumentException("Duplicate cache key can't be used , please use an unique key for cache."); currentCacheInfo = CreateCacheInfo(cacheInfoAtt, methodInfo, funcInstanc, key); } try { if (typeof(IQueryable).IsAssignableFrom(methodInfo.ReturnType) && parames.Length > 0 && typeof(IQueryable).IsAssignableFrom(parames[0].ParameterType)) { if (!isRepositoryAssembly) { throw new NotSupportedException("Queryable Cache just can use in Repository Layer."); } var repository = (IRepositoryCache)Activator.CreateInstance(methodInfo.DeclaringType, Activator.CreateInstance(dBContext)); currentCacheInfo.Repository = repository; if (parames.Length == 1) { var cacheDataProviderType = typeof(QueryableCacheDataProvider <>); Type[] typeArgs = methodInfo.ReturnType.GenericTypeArguments; var cacheDataProviderGenericType = cacheDataProviderType.MakeGenericType(typeArgs); var returnCacheType = typeof(List <>).MakeGenericType(methodInfo.ReturnType.GenericTypeArguments[0]); CacheWCFTypeHelper.typeList.Add(cacheDataProviderGenericType); CacheWCFTypeHelper.typeList.Add(methodInfo.ReturnType.GenericTypeArguments[0]); CacheWCFTypeHelper.typeList.Add(returnCacheType); // if (currentCacheInfo.EnableUseCacheServer) // CacheWCFTypeHelper.typeList.Add(methodInfo.ReturnType); object queryableCacheExecution = Activator.CreateInstance(cacheDataProviderGenericType, new object[] { currentCacheInfo }); if (currentCacheInfo.FrequencyOfBuilding == 0) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); if (!cacheInfoAtt.DisableCache) { (typeof(CacheBase)).GetMethod("RefreshCache").MakeGenericMethod(returnCacheType).Invoke(null, new object[] { queryableCacheExecution, currentCacheInfo }); } stopwatch.Stop(); currentCacheInfo.FrequencyOfBuilding += 1; currentCacheInfo.BuildingTime += new TimeSpan(stopwatch.ElapsedTicks); } if (currentCacheInfo.CacheRefreshingKind == CacheRefreshingKind.Slide) { PeriodicTaskFactory p = new PeriodicTaskFactory((pt) => { if (currentCacheInfo.CountOfWaitingThreads < 3) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); ((IQueryableCacheDataProvider)queryableCacheExecution).DbContext = AppBase.DependencyInjectionFactory.CreateContextInstance(); (typeof(CacheBase)).GetMethod("RefreshCache").MakeGenericMethod(returnCacheType).Invoke(null, new object[] { queryableCacheExecution, currentCacheInfo }); stopwatch.Stop(); currentCacheInfo.FrequencyOfBuilding += 1; currentCacheInfo.BuildingTime += new TimeSpan(stopwatch.ElapsedTicks); } }, new TimeSpan(0, 0, currentCacheInfo.AutoRefreshInterval), new TimeSpan(0, 0, currentCacheInfo.AutoRefreshInterval)); p.Start(); } else { if (currentCacheInfo.CacheRefreshingKind == CacheRefreshingKind.SqlDependency) { if (currentCacheInfo.EnableSaveCacheOnHDD && currentCacheInfo.EnableToFetchOnlyChangedDataFromDB) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); if (!cacheInfoAtt.DisableCache) { ((IQueryableCacheDataProvider)queryableCacheExecution).DbContext = AppBase.DependencyInjectionFactory.CreateContextInstance(); (typeof(CacheBase)).GetMethod("RefreshCache").MakeGenericMethod(returnCacheType).Invoke(null, new object[] { queryableCacheExecution, currentCacheInfo }); } stopwatch.Stop(); currentCacheInfo.FrequencyOfBuilding += 1; currentCacheInfo.BuildingTime += new TimeSpan(stopwatch.ElapsedTicks); } var typeOfSqlNotifier = typeof(IImmediateSqlNotificationRegister <>) .MakeGenericType(currentCacheInfo.Repository.GetDomainModelType()); IImmediateSqlNotificationRegisterBase immediateSqlNotificationRegister = (IImmediateSqlNotificationRegisterBase) AppBase.DependencyInjectionManager.Resolve(typeOfSqlNotifier, new ParameterOverride("context", ((IQueryableCacheDataProvider)queryableCacheExecution).DbContext), new ParameterOverride("query", ((IQueryableCacheDataProvider)queryableCacheExecution).GetQuery())); using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = currentCacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Message = $"CacheSql Dependency {currentCacheInfo.Name} before configouration on startup at {DateTime.Now.ToString()} ..."; trace.Data["State"] = "config"; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } immediateSqlNotificationRegister.OnChanged += (object sender, SqlNotificationEventArgs e) => { if (currentCacheInfo.CountOfWaitingThreads < 3) { using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = currentCacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Message = $"CacheSql Dependency {currentCacheInfo.Name} before changing at {DateTime.Now.ToString()} ..."; trace.Data["State"] = "changing"; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); ((IQueryableCacheDataProvider)queryableCacheExecution).DbContext = AppBase.DependencyInjectionFactory.CreateContextInstance(); immediateSqlNotificationRegister.Init(((IQueryableCacheDataProvider)queryableCacheExecution).DbContext, ((IQueryableCacheDataProvider)queryableCacheExecution).GetQuery(), currentCacheInfo); ExcecuteQueryForRefreshingSqlDependencyCache(currentCacheInfo, returnCacheType, queryableCacheExecution, 500); stopwatch.Stop(); currentCacheInfo.FrequencyOfBuilding += 1; currentCacheInfo.BuildingTime += new TimeSpan(stopwatch.ElapsedTicks); using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = currentCacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Message = $"CacheSql Dependency {currentCacheInfo.Name} was changed at {DateTime.Now.ToString()} ..."; trace.Data["State"] = "changing"; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } } }; using (var trace = new Trace.TraceDto()) { trace.TraceKey = "CacheSqlDependency"; trace.Data["CacheName"] = currentCacheInfo.Name; trace.Data["DateTime"] = DateTime.Now.ToString(); trace.Message = $"CacheSql Dependency {currentCacheInfo.Name} was configured on startup at {DateTime.Now.ToString()} ..."; trace.Data["State"] = "config"; Core.Cmn.AppBase.TraceWriter.SubmitData(trace); } } } } if (currentCacheInfo.EnableToFetchOnlyChangedDataFromDB && !currentCacheInfo.DisableToSyncDeletedRecord_JustIfEnableToFetchOnlyChangedDataFromDB) { CacheManagementRepository.CreateSqlTriggerForDetectingDeletedRecords(string.Format("{0}.{1}", repository.Schema, repository.TableName), repository.KeyName); } } else { if (isRepositoryAssembly) { throw new NotSupportedException("Functional Cache just can use in Service Layer."); } var Service = (IServiceCache)Activator.CreateInstance(methodInfo.DeclaringType, Activator.CreateInstance(dBContext)); Core.Cmn.AppBase.TraceWriter.SubmitData(new Trace.TraceDto { Message = $"{currentCacheInfo.Name} BuildCachesInAssembly start..." }); currentCacheInfo.Service = Service; Type cacheDataProviderType = null; if (parames.Length == 0) { cacheDataProviderType = typeof(FunctionalCacheDataProvider <>); var cacheDataProviderGenericType = AddAndGetCacheDataProviderTypeForSerialization(methodInfo, cacheDataProviderType); object functionalCacheExecution = Activator.CreateInstance(cacheDataProviderGenericType, new object[] { currentCacheInfo }); if (currentCacheInfo.FrequencyOfBuilding == 0) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); if (!cacheInfoAtt.DisableCache) { (typeof(CacheBase)).GetMethod("RefreshCache").MakeGenericMethod(methodInfo.ReturnType).Invoke(null, new object[] { functionalCacheExecution, currentCacheInfo }); } stopwatch.Stop(); currentCacheInfo.FrequencyOfBuilding += 1; currentCacheInfo.BuildingTime += new TimeSpan(stopwatch.ElapsedTicks); } if (currentCacheInfo.CacheRefreshingKind == CacheRefreshingKind.Slide) { PeriodicTaskFactory p = new PeriodicTaskFactory((pt) => { if (currentCacheInfo.CountOfWaitingThreads < 3) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); (typeof(CacheBase)).GetMethod("RefreshCache").MakeGenericMethod(methodInfo.ReturnType).Invoke(null, new object[] { functionalCacheExecution, currentCacheInfo }); stopwatch.Stop(); currentCacheInfo.FrequencyOfBuilding += 1; currentCacheInfo.BuildingTime += new TimeSpan(stopwatch.ElapsedTicks); } }, new TimeSpan(0, 0, currentCacheInfo.AutoRefreshInterval), new TimeSpan(0, 0, currentCacheInfo.AutoRefreshInterval)); p.Start(); } } else { if (parames.Length == 1) { cacheDataProviderType = typeof(FunctionalCacheDataProvider <,>); } if (parames.Length == 2) { cacheDataProviderType = typeof(FunctionalCacheDataProvider <, ,>); } if (parames.Length == 3) { cacheDataProviderType = typeof(FunctionalCacheDataProvider <, , ,>); } if (parames.Length == 4) { cacheDataProviderType = typeof(FunctionalCacheDataProvider <, , , ,>); } if (parames.Length == 5) { cacheDataProviderType = typeof(FunctionalCacheDataProvider <, , , , ,>); } AddAndGetCacheDataProviderTypeForSerialization(methodInfo, cacheDataProviderType); } Core.Cmn.AppBase.TraceWriter.SubmitData(new Trace.TraceDto { Message = $"{currentCacheInfo.Name} BuildCachesInAssembly done." }); } } catch (Exception exception) { Core.Cmn.AppBase.LogService.Handle(exception, $"{exception.Message}. Cache name: {currentCacheInfo?.Name}"); throw; } currentCacheInfo.LastBuildDateTime = DateTime.Now; } else { if (cacheInfoAtt.EnableAutomaticallyAndPeriodicallyRefreshCache) { throw new NotSupportedException($"a generic method can't call automatically for cache.If you want to use generic method set '{nameof(cacheInfoAtt.CacheRefreshingKind)}' = {nameof(CacheRefreshingKind.Slide)} in CacheableAttribute"); } } } else { throw new NotSupportedException("Cacheable Attribute can't use on Non static methods, because we can't work on nostatic method for caching."); } } } }