Skip to content

Commit

Permalink
Add Cache, Transaction, Performance aspects
Browse files Browse the repository at this point in the history
  • Loading branch information
Ahmet Çetinkaya committed Mar 6, 2021
1 parent 8621c43 commit f17c7b3
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 3 deletions.
6 changes: 5 additions & 1 deletion Business/Concrete/CarImageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Business.Abstract;
using Business.BusinessAspects.Autofac;
using Business.Constants;
using Core.Aspects.Autofac.Caching;
using Core.Utilities.Business;
using Core.Utilities.FileSystems;
using Core.Utilities.Results;
Expand All @@ -23,7 +24,6 @@ public CarImageManager(ICarImageDal carImageDal)
_carImageDal = carImageDal;
}


public IDataResult<CarImage> GetById(int id)
{
return new SuccessDataResult<CarImage>(_carImageDal.Get(c => c.Id == id));
Expand All @@ -34,6 +34,7 @@ public IDataResult<List<CarImage>> GetAll()
return new SuccessDataResult<List<CarImage>>(_carImageDal.GetAll());
}

[CacheAspect]
public IDataResult<List<CarImage>> GetImagesByCarId(int carId)
{
var result = _carImageDal.GetAll(c => c.CarId == carId);
Expand All @@ -43,6 +44,7 @@ public IDataResult<List<CarImage>> GetImagesByCarId(int carId)
}

[SecuredOperation("carimage.add,moderator,admin")]
[CacheRemoveAspect("ICarImageService.Get")]
public IResult Add(CarImage carImage, IFormFile file)
{
var result = BusinessRules.Run(
Expand All @@ -56,6 +58,7 @@ public IResult Add(CarImage carImage, IFormFile file)
}

[SecuredOperation("carimage.update,moderator,admin")]
[CacheRemoveAspect("ICarImageService.Get")]
public IResult Update(CarImage carImage, IFormFile file)
{
var carImageToUpdate = _carImageDal.Get(c => c.Id == carImage.Id);
Expand All @@ -67,6 +70,7 @@ public IResult Update(CarImage carImage, IFormFile file)
}

[SecuredOperation("carimage.delete,moderator,admin")]
[CacheRemoveAspect("ICarImageService.Get")]
public IResult Delete(CarImage carImage)
{
new FileManagerOnDisk().Delete(carImage.ImagePath);
Expand Down
12 changes: 11 additions & 1 deletion Business/Concrete/CarManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
using Business.Abstract;
using Business.BusinessAspects.Autofac;
using Business.Constants;
using Core.Aspects.Autofac;
using Core.Aspects.Autofac.Caching;
using Core.Aspects.Autofac.Validation;
using Core.Utilities.Results;
using DataAccess.Abstract;
using Entities.Concrete;
Expand All @@ -20,47 +21,56 @@ public CarManager(ICarDal carDal)
_carDal = carDal;
}

[CacheAspect]
public IDataResult<Car> GetById(int id)
{
return new SuccessDataResult<Car>(_carDal.Get(c => c.Id == id));
}

[CacheAspect]
public IDataResult<List<Car>> GetAll()
{
return new SuccessDataResult<List<Car>>(_carDal.GetAll());
}

[CacheAspect]
public IDataResult<List<CarDetailDto>> GetCarDetails()
{
return new SuccessDataResult<List<CarDetailDto>>(_carDal.GetCarDetails());
}

[CacheAspect]
public IDataResult<List<Car>> GetCarsByBrandId(int id)
{
return new SuccessDataResult<List<Car>>(_carDal.GetAll(c => c.BrandId == id));
}

[CacheAspect]
public IDataResult<List<Car>> GetCarsByColorId(int id)
{
return new SuccessDataResult<List<Car>>(_carDal.GetAll(c => c.ColorId == id));
}

[SecuredOperation("car.add,moderator,admin")]
[ValidationAspect(typeof(CarValidator))]
[CacheRemoveAspect("ICarService.Get")]
public IResult Add(Car car)
{
_carDal.Add(car);
return new SuccessResult(Messages.CarAdded);
}

[SecuredOperation("car.update,moderator,admin")]
[ValidationAspect(typeof(CarValidator))]
[CacheRemoveAspect("ICarService.Get")]
public IResult Update(Car car)
{
_carDal.Update(car);
return new SuccessResult(Messages.CarUpdated);
}

[SecuredOperation("car.delete,moderator,admin")]
[CacheRemoveAspect("ICarService.Get")]
public IResult Delete(Car car)
{
_carDal.Delete(car);
Expand Down
36 changes: 36 additions & 0 deletions Core/Aspects/Autofac/Caching/CacheAspect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Linq;
using Castle.DynamicProxy;
using Core.CrossCuttingConcerns.Caching;
using Core.Utilities.Interceptors;
using Core.Utilities.IoC;
using Microsoft.Extensions.DependencyInjection;

namespace Core.Aspects.Autofac.Caching
{
public class CacheAspect : MethodInterception
{
private readonly ICacheManager _cacheManager;
private readonly int _duration;

public CacheAspect(int duration = 60)
{
_duration = duration;
_cacheManager = ServiceTool.ServiceProvider.GetService<ICacheManager>();
}

public override void Intercept(IInvocation invocation)
{
var methodName = string.Format($"{invocation.Method.ReflectedType.FullName}.{invocation.Method.Name}");
var arguments = invocation.Arguments.ToList();
var key = $"{methodName}({string.Join(",", arguments.Select(x => x?.ToString() ?? "<Null>"))})";
if (_cacheManager.IsAdd(key))
{
invocation.ReturnValue = _cacheManager.Get(key);
return;
}

invocation.Proceed();
_cacheManager.Add(key, invocation.ReturnValue, _duration);
}
}
}
25 changes: 25 additions & 0 deletions Core/Aspects/Autofac/Caching/CacheRemoveAspect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Castle.DynamicProxy;
using Core.CrossCuttingConcerns.Caching;
using Core.Utilities.Interceptors;
using Core.Utilities.IoC;
using Microsoft.Extensions.DependencyInjection;

namespace Core.Aspects.Autofac.Caching
{
public class CacheRemoveAspect : MethodInterception
{
private readonly ICacheManager _cacheManager;
private readonly string _pattern;

public CacheRemoveAspect(string pattern)
{
_pattern = pattern;
_cacheManager = ServiceTool.ServiceProvider.GetService<ICacheManager>();
}

protected override void OnSuccess(IInvocation invocation)
{
_cacheManager.RemoveByPattern(_pattern);
}
}
}
34 changes: 34 additions & 0 deletions Core/Aspects/Autofac/Performance/PerformanceAspect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Diagnostics;
using Castle.DynamicProxy;
using Core.Utilities.Interceptors;
using Core.Utilities.IoC;
using Microsoft.Extensions.DependencyInjection;

namespace Core.Aspects.Autofac.Performance
{
public class PerformanceAspect : MethodInterception
{
private readonly int _interval;
private readonly Stopwatch _stopwatch;

public PerformanceAspect(int interval)
{
_interval = interval;
_stopwatch = ServiceTool.ServiceProvider.GetService<Stopwatch>();
}


protected override void OnBefore(IInvocation invocation)
{
_stopwatch.Start();
}

protected override void OnAfter(IInvocation invocation)
{
if (_stopwatch.Elapsed.TotalSeconds > _interval)
Debug.WriteLine(
$"Performance : {invocation.Method.DeclaringType.FullName}.{invocation.Method.Name}-->{_stopwatch.Elapsed.TotalSeconds}");
_stopwatch.Reset();
}
}
}
27 changes: 27 additions & 0 deletions Core/Aspects/Autofac/Transaction/TransactionScopeAspect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Transactions;
using Castle.DynamicProxy;
using Core.Utilities.Interceptors;

namespace Core.Aspects.Autofac.Transaction
{
public class TransactionScopeAspect : MethodInterception
{
public override void Intercept(IInvocation invocation)
{
using (var transactionScope = new TransactionScope())
{
try
{
invocation.Proceed();
transactionScope.Complete();
}
catch (Exception e)
{
transactionScope.Dispose();
throw;
}
}
}
}
}
12 changes: 12 additions & 0 deletions Core/CrossCuttingConcerns/Caching/ICacheManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Core.CrossCuttingConcerns.Caching
{
public interface ICacheManager
{
void Add(string key, object value, int duration);
T Get<T>(string key);
object Get(string key);
bool IsAdd(string key);
void Remove(string key);
void RemoveByPattern(string pattern);
}
}
68 changes: 68 additions & 0 deletions Core/CrossCuttingConcerns/Caching/Microsoft/MemoryCacheManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Core.Utilities.IoC;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;

namespace Core.CrossCuttingConcerns.Caching.Microsoft
{
public class MemoryCacheManager : ICacheManager
{
private readonly IMemoryCache _memoryCache;

public MemoryCacheManager(IMemoryCache memoryCache)
{
_memoryCache = ServiceTool.ServiceProvider.GetService<IMemoryCache>();
}

public void Add(string key, object value, int duration)
{
_memoryCache.Set(key, value, TimeSpan.FromMinutes(duration));
}

public T Get<T>(string key)
{
return _memoryCache.Get<T>(key);
}

public object Get(string key)
{
return _memoryCache.Get(key);
}

public bool IsAdd(string key)
{
return _memoryCache.TryGetValue(key, out _);
}

public void Remove(string key)
{
_memoryCache.Remove(key);
}

public void RemoveByPattern(string pattern)
{
var cacheEntriesCollectionDefinition = typeof(MemoryCache).GetProperty("EntriesCollection",
BindingFlags.NonPublic | BindingFlags.Instance);
var cacheEntriesCollection = cacheEntriesCollectionDefinition.GetValue(_memoryCache) as dynamic;
var cacheCollectionValues = new List<ICacheEntry>();

foreach (var cacheItem in cacheEntriesCollection)
{
ICacheEntry cacheItemValue = cacheItem.GetType().GetProperty("Value").GetValue(cacheItem, null);
cacheCollectionValues.Add(cacheItemValue);
}

var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
var keysToRemove = cacheCollectionValues
.Where(d => regex.IsMatch(d.Key.ToString()))
.Select(d => d.Key)
.ToList();

foreach (var key in keysToRemove) _memoryCache.Remove(key);
}
}
}
8 changes: 7 additions & 1 deletion Core/DependencyResolvers/CoreModule.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Core.Utilities.IoC;
using System.Diagnostics;
using Core.CrossCuttingConcerns.Caching;
using Core.CrossCuttingConcerns.Caching.Microsoft;
using Core.Utilities.IoC;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -8,7 +11,10 @@ public class CoreModule : ICoreModule
{
public void Load(IServiceCollection serviceCollection)
{
serviceCollection.AddMemoryCache();
serviceCollection.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
serviceCollection.AddSingleton<ICacheManager, MemoryCacheManager>();
serviceCollection.AddSingleton<Stopwatch>();
}
}
}
2 changes: 2 additions & 0 deletions Core/Utilities/Interceptors/AspectInterceptorSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Linq;
using System.Reflection;
using Castle.DynamicProxy;
using Core.Aspects.Autofac.Performance;

namespace Core.Utilities.Interceptors
{
Expand All @@ -14,6 +15,7 @@ public IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IIntercep
var methodAttributes = type.GetMethod(method.Name)
.GetCustomAttributes<MethodInterceptionBaseAttribute>(true);
classAttributes.AddRange(methodAttributes);
classAttributes.Add(new PerformanceAspect(5));

return classAttributes.OrderBy(x => x.Priority).ToArray();
}
Expand Down

0 comments on commit f17c7b3

Please sign in to comment.