0. Preface
I wrote a few articles before introducing some AOP knowledge, but the posture of AOP has not been revealed yet.
Maybe the posture is more beautiful. Everyone will be interested in AOP.
The content will be roughly divided into the following articles (after all, I is a lazy man, too tired to finish writing at once, and there is no motivation):
- AOP posture to simplify the use of
MemoryCache
- The posture of AOP to simplify the mixed use of
MemoryCache
and DistributedCache
- The posture of AOP how to turn
HttpClient
into declarative
As for the AOP framework, the example here will still use my own dynamic proxy AOP framework based on emit: https://github.com/fs7744/Norns.Urd
After all, I wrote it myself, so it is very convenient to modify/add functions.
In case you have any questions (although I probably won't have any), I can answer it too. (Of course, if everyone agrees, giving a star on github will be really fun).
1. Review How to Use MemoryCache
var cache = ServiceProvider.GetRequiredService<IMemoryCache>();
var r = await cache.GetOrCreateAsync(cacheKey, async e =>
{
var rr = await do();
e.AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow;
return rr;
});
`MemoryCache
` itself has been encapsulated so simple that it can be used. But, every time we use it, we still have to rewrite similar code like this. Of course, we all have super strong Ctrl+c and Ctrl+v capabilities. This little repetitive code is drizzle, the above w lines of code are all small scenes.
However, this kind of code is written in the same way as students in school. How can it reflect the fact that we have been working overtime for decades? We want to make these students/interns not understand our code, so that they can’t see `GetOrCreateAsync
`.
Let them not find how to run the breakpoint in `do()
` when debugging. Only in this way can we show the strength of the Sweeper: Come, kid, let me teach you a new skill.
2. Write a Cache AOP Interceptor
In Norns.Urd
, Interceptor
is the core where users can insert their own logic in methods.
The standard structure is `IInterceptor
`.
public interface IInterceptor
{
int Order { get; }
void Invoke(AspectContext context, AspectDelegate next);
Task InvokeAsync(AspectContext context, AsyncAspectDelegate next);
bool CanAspect(MethodInfo method);
}
Here, we will use the simplest way for everyone to understand it simply: Use `AbstractInterceptorAttribute
`. A very simple example is as follows:
public class CacheAttribute : AbstractInterceptorAttribute
{
private readonly TimeSpan absoluteExpirationRelativeToNow;
private readonly string cacheKey;
public CacheAttribute(string cacheKey, string absoluteExpirationRelativeToNow)
{
this.cacheKey = cacheKey;
this.absoluteExpirationRelativeToNow =
TimeSpan.Parse(absoluteExpirationRelativeToNow);
}
public override async Task InvokeAsync
(AspectContext context, AsyncAspectDelegate next)
{
var cache = context.ServiceProvider.GetRequiredService<IMemoryCache>();
var r = await cache.GetOrCreateAsync(cacheKey, async e =>
{
await next(context);
e.AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow;
return context.ReturnValue;
});
context.ReturnValue = r;
}
}
3. Do a Test
Just use simple test code like this:
public interface ITestCacheClient
{
string Say(string v);
}
public class TestCacheClient : ITestCacheClient
{
public string Say(string v) => v;
}
static class Program
{
static void Main(string[] args)
{
var client = new ServiceCollection()
.AddMemoryCache()
.AddSingleton<ITestCacheClient, TestCacheClient>()
.ConfigureAop()
.BuildServiceProvider()
.GetRequiredService<ITestCacheClient>();
Console.WriteLine(client.Say("Hello World!"));
Console.WriteLine(client.Say("Hello Two!"));
Thread.Sleep(3000);
Console.WriteLine(client.Say("Hello Two!"));
}
}
Console result:
Hello World!
Hello Two!
Hello Two!
Add cache settings:
public class TestCacheClient : ITestCacheClient
{
[Cache(nameof(Say), "00:00:03")]
public string Say(string v) => v;
}
Console result:
Hello World!
Hello World!
Hello Two!
The example codes are all at https://github.com/fs7744/AopDemoList/tree/master/MakeMemoryChacheSimple.
A more comprehensive example of handling the situation is at https://github.com/fs7744/Norns.Urd/tree/main/src.
History
- 27th December, 2020: Initial version