Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build/version.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<EasyCachingSQLitePackageVersion>0.5.2</EasyCachingSQLitePackageVersion>
<EasyCachingInMemoryPackageVersion>0.5.2</EasyCachingInMemoryPackageVersion>
<EasyCachingHybridPackageVersion>0.5.2</EasyCachingHybridPackageVersion>
<EasyCachingAspectCorePackageVersion>0.5.2</EasyCachingAspectCorePackageVersion>
<EasyCachingCastlePackageVersion>0.5.2</EasyCachingCastlePackageVersion>
<EasyCachingAspectCorePackageVersion>0.5.2.1</EasyCachingAspectCorePackageVersion>
<EasyCachingCastlePackageVersion>0.5.2.1</EasyCachingCastlePackageVersion>
<EasyCachingResponseCachingPackageVersion>0.5.2</EasyCachingResponseCachingPackageVersion>
<EasyCachingJsonPackageVersion>0.5.2</EasyCachingJsonPackageVersion>
<EasyCachingMessagePackPackageVersion>0.5.2</EasyCachingMessagePackPackageVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ public async Task<string> AspectcoreAsync(int type = 1)
var res = await _aService.GetDemoAsync(999);
return $"{res.Id}-{res.Name}-{res.CreateTime}";
}
else if (type == 3)
{
var res = await _aService.GetDemoListAsync(999);
return $"{res.Count}";
}
else
{
return await Task.FromResult("wait");
Expand Down Expand Up @@ -104,6 +109,11 @@ public async Task<string> CastleAsync(int type = 1)
var res = await _cService.GetDemoAsync(999);
return $"{res.Id}-{res.Name}-{res.CreateTime}";
}
else if (type == 3)
{
var res = await _aService.GetDemoListAsync(999);
return $"{res.Count}";
}
else
{
return await Task.FromResult<string>("wait");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public interface IAspectCoreService //: EasyCaching.Core.Internal.IEasyCaching
[EasyCachingAble(Expiration = 10)]
Task<Demo> GetDemoAsync(int id);

[EasyCachingAble(Expiration = 10)]
Task<System.Collections.Generic.List<Demo>> GetDemoListAsync(int id);


[EasyCachingAble(Expiration = 10)]
Demo GetDemo(int id);
}
Expand All @@ -47,11 +51,21 @@ public Task<Demo> GetDemoAsync(int id)
return Task.FromResult(new Demo { Id = id, CreateTime = System.DateTime.Now, Name = "catcher" });
}

public Task<System.Collections.Generic.List<Demo>> GetDemoListAsync(int id)
{
return Task.FromResult(new System.Collections.Generic.List<Demo>() { new Demo { Id = id, CreateTime = System.DateTime.Now, Name = "catcher" } });
}

public async Task<string> GetUtcTimeAsync()
{
return await Task.FromResult<string>(System.DateTimeOffset.UtcNow.ToString());
}

public async Task DeleteSomethingAsync(int id)
{
await Task.Run(() => System.Console.WriteLine("Handle delete something.."));
}

public string PutSomething(string str)
{
return str;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public interface ICastleService
[EasyCachingAble(Expiration = 10)]
Task<Demo> GetDemoAsync(int id);

[EasyCachingAble(Expiration = 10)]
Task<System.Collections.Generic.List<Demo>> GetDemoListAsync(int id);

[EasyCachingAble(Expiration = 10)]
Demo GetDemo(int id);
}
Expand All @@ -47,6 +50,11 @@ public Task<Demo> GetDemoAsync(int id)
return Task.FromResult(new Demo { Id = id, CreateTime = System.DateTime.Now, Name = "catcher" });
}

public Task<System.Collections.Generic.List<Demo>> GetDemoListAsync(int id)
{
return Task.FromResult(new System.Collections.Generic.List<Demo>() { new Demo { Id = id, CreateTime = System.DateTime.Now, Name = "catcher" } });
}

public async Task<string> GetUtcTimeAsync()
{
return await Task.FromResult<string>(System.DateTimeOffset.UtcNow.ToString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,14 @@ private async Task ProceedAbleAsync(AspectContext context, AspectDelegate next)
{
if (context.ServiceMethod.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(EasyCachingAbleAttribute)) is EasyCachingAbleAttribute attribute)
{
var cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix);
var cacheValue = await CacheProvider.GetAsync(cacheKey, context.ServiceMethod.ReturnType);

var returnType = context.IsAsync()
? context.ServiceMethod.ReturnType.GetGenericArguments().First()
: context.ServiceMethod.ReturnType;

var cacheKey = KeyGenerator.GetCacheKey(context.ServiceMethod, context.Parameters, attribute.CacheKeyPrefix);

object cacheValue = await CacheProvider.GetAsync(cacheKey, returnType);

if (cacheValue != null)
{
if (context.IsAsync())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="4.5.0" />
<PackageReference Include="Autofac" Version="4.8.1" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.3.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
</ItemGroup>
</Project>
53 changes: 48 additions & 5 deletions src/EasyCaching.Interceptor.Castle/EasyCachingInterceptor.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
namespace EasyCaching.Interceptor.Castle
{
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using EasyCaching.Core;
using EasyCaching.Core.Interceptor;
Expand All @@ -22,6 +24,12 @@ public class EasyCachingInterceptor : IInterceptor
/// </summary>
private readonly IEasyCachingKeyGenerator _keyGenerator;

/// <summary>
/// The typeof task result method.
/// </summary>
private static readonly ConcurrentDictionary<Type, MethodInfo>
TypeofTaskResultMethod = new ConcurrentDictionary<Type, MethodInfo>();

/// <summary>
/// Initializes a new instance of the <see cref="T:EasyCaching.Interceptor.Castle.EasyCachingInterceptor"/> class.
/// </summary>
Expand Down Expand Up @@ -63,22 +71,47 @@ private void ProceedAble(IInvocation invocation)

if (serviceMethod.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(EasyCachingAbleAttribute)) is EasyCachingAbleAttribute attribute)
{
var cacheKey = _keyGenerator.GetCacheKey(serviceMethod, invocation.Arguments, attribute.CacheKeyPrefix);
var returnType = serviceMethod.IsReturnTask()
? serviceMethod.ReturnType.GetGenericArguments().First()
: serviceMethod.ReturnType;

var cacheValue = (_cacheProvider.GetAsync(cacheKey, serviceMethod.ReturnType)).GetAwaiter().GetResult();
var cacheKey = _keyGenerator.GetCacheKey(serviceMethod, invocation.Arguments, attribute.CacheKeyPrefix);

var cacheValue = (_cacheProvider.GetAsync(cacheKey, returnType)).GetAwaiter().GetResult();


if (cacheValue != null)
{
invocation.ReturnValue = cacheValue;
if (serviceMethod.IsReturnTask())
{
invocation.ReturnValue =
TypeofTaskResultMethod.GetOrAdd(returnType, t => typeof(Task).GetMethods().First(p => p.Name == "FromResult" && p.ContainsGenericParameters).MakeGenericMethod(returnType)).Invoke(null, new object[] { cacheValue });
}
else
{
invocation.ReturnValue = cacheValue;
}
}
else
{
// Invoke the method if we don't have a cache hit
invocation.Proceed();

if (!string.IsNullOrWhiteSpace(cacheKey) && invocation.ReturnValue != null)
_cacheProvider.Set(cacheKey, invocation.ReturnValue, TimeSpan.FromSeconds(attribute.Expiration));
{
if (serviceMethod.IsReturnTask())
{
//get the result
var returnValue = invocation.UnwrapAsyncReturnValue().Result;

_cacheProvider.Set(cacheKey, returnValue, TimeSpan.FromSeconds(attribute.Expiration));
}
else
{
_cacheProvider.Set(cacheKey, invocation.ReturnValue, TimeSpan.FromSeconds(attribute.Expiration));
}
}

}
}
else
Expand All @@ -100,7 +133,17 @@ private void ProcessPut(IInvocation invocation)
{
var cacheKey = _keyGenerator.GetCacheKey(serviceMethod, invocation.Arguments, attribute.CacheKeyPrefix);

_cacheProvider.Set(cacheKey, invocation.ReturnValue, TimeSpan.FromSeconds(attribute.Expiration));
if (serviceMethod.IsReturnTask())
{
//get the result
var returnValue = invocation.UnwrapAsyncReturnValue().Result;

_cacheProvider.Set(cacheKey, returnValue, TimeSpan.FromSeconds(attribute.Expiration));
}
else
{
_cacheProvider.Set(cacheKey, invocation.ReturnValue, TimeSpan.FromSeconds(attribute.Expiration));
}
}
}

Expand Down
95 changes: 95 additions & 0 deletions src/EasyCaching.Interceptor.Castle/ReflectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using Castle.DynamicProxy;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace EasyCaching.Interceptor.Castle
{
public static class ReflectionExtensions
{
public static bool IsReturnTask(this MethodInfo methodInfo)
{
if (methodInfo == null)
{
throw new ArgumentNullException(nameof(methodInfo));
}
var returnType = methodInfo.ReturnType.GetTypeInfo();
return returnType.IsTaskWithResult();
}

public static Task<object> UnwrapAsyncReturnValue(this IInvocation invocation)
{
if (invocation == null)
{
throw new ArgumentNullException(nameof(invocation));
}

var serviceMethod = invocation.Method ?? invocation.MethodInvocationTarget;

if (!serviceMethod.IsReturnTask())
{
throw new InvalidOperationException("This operation only support asynchronous method.");
}

var returnValue = invocation.ReturnValue;
if (returnValue == null)
{
return null;
}

var returnTypeInfo = returnValue.GetType().GetTypeInfo();
return Unwrap(returnValue, returnTypeInfo);
}

private static async Task<object> Unwrap(object value, TypeInfo valueTypeInfo)
{
object result = null;

if (valueTypeInfo.IsTaskWithResult())
{
// Is there better solution to unwrap ?
result = (object) (await (dynamic) value);
}
else if (value is Task)
{
return null;
}
else
{
result = value;
}

if (result == null)
{
return null;
}

var resultTypeInfo = result.GetType().GetTypeInfo();
if (IsAsyncType(resultTypeInfo))
{
return Unwrap(result, resultTypeInfo);
}

return result;
}

private static bool IsAsyncType(TypeInfo typeInfo)
{
if (typeInfo.IsTask())
{
return true;
}

if (typeInfo.IsTaskWithResult())
{
return true;
}


return false;
}
}
}
31 changes: 31 additions & 0 deletions src/EasyCaching.Interceptor.Castle/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Concurrent;
using System.Reflection;
using System.Threading.Tasks;

namespace EasyCaching.Interceptor.Castle
{
public static class TypeExtensions
{
private static readonly ConcurrentDictionary<TypeInfo, bool> isTaskOfTCache = new ConcurrentDictionary<TypeInfo, bool>();

public static bool IsTaskWithResult(this TypeInfo typeInfo)
{
if (typeInfo == null)
{
throw new ArgumentNullException(nameof(typeInfo));
}
return isTaskOfTCache.GetOrAdd(typeInfo, Info => Info.IsGenericType && typeof(Task).GetTypeInfo().IsAssignableFrom(Info));
}

public static bool IsTask(this TypeInfo typeInfo)
{
if (typeInfo == null)
{
throw new ArgumentNullException(nameof(typeInfo));
}
return typeInfo.AsType() == typeof(Task);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ protected virtual async Task Interceptor_Put_With_Task_Method_Should_Succeed()

var key = _keyGenerator.GetCacheKey(method, new object[] { 1, "123" }, "CastleExample");

var value = _cachingProvider.Get<Task<string>>(key);
var value = _cachingProvider.Get<string>(key);

Assert.True(value.HasValue);
Assert.Equal(str, value.Value.Result);
Assert.Equal(str, value.Value);
}

[Fact]
Expand Down