The foreword 0.

Before writing a few articles introduced some AOP knowledge, but has not yet revealed AOP posture, perhaps a bit beautiful posture, we will be a little interested in AOP content will be roughly divided into the following several :(after all, people lazy, all of a sudden to write too tired, no motivation)

  1. AOP posture for simplified MemoryCache usage
  2. Simplified AOP posture for mixing MemoryCache and DistributedCache usage
  3. How does AOP posture turn HttpClient into declarative

As for the AOP framework, here the example will still use my own dynamic proxy AOP framework based on the EMIT implementation: github.com/fs7744/Norn… After all, it is my own writing, magic change/add functions are very convenient, in case you have any questions, (although probably not), I can answer, (of course, if you recognize, give a star on Github, it is really too happy)

1. The body

1.1 Review How MemoryCache is used

var cache = ServiceProvider.GetRequiredService<IMemoryCache>();
var r = await cache.GetOrCreateAsync(cacheKey, async e =>
            {
                var rr = await do(a); e.AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow;return rr;
            });
Copy the code

MemoryCache itself is packaged in such a simple way that it can be used, but we still have to repeat the same code every time we use it. Of course, we all have CTRL + C and CTRL + V capabilities, so it’s a little bit trivial. W lines of code a shuttle is a small scene,

But how can a code like this, written like a student at school, reflect the fact that we’ve been working overtime for decades? We want to make our code invisible to the students/internsGetOrCreateAsyncLet them debug itdo()The break point inside won’t run so that we can demonstrate the strength of the sweeping monk: Here, little friend, I’ll teach you the new pose

1.2 Forced to set sail

1.2.1 Forced Core – Interceptor

In Norns.urd, the Interceptor Interceptor is the core of the logic that users can insert into methods. The standard structure is IInterceptor

public interface IInterceptor
{
    // The user can customize the Order of interceptors by Order. The Order is ASC, and both global interceptors and display interceptors are included in the Order
    int Order { get; }

    // Synchronize intercepting methods
    void Invoke(AspectContext context, AspectDelegate next);

    // asynchronous intercepting methods
    Task InvokeAsync(AspectContext context, AsyncAspectDelegate next);

    // Can you set how the interceptor chooses whether the filter intercepts methods or not, in addition to NonAspectAttribute and global NonPredicates that affect the filter
    bool CanAspect(MethodInfo method);
}
Copy the code

Here we for everybody to understand simple, just use the most simple way to do: use AbstractInterceptorAttribute a very simple example is as follows:

    public class CacheAttribute : AbstractInterceptorAttribute
    {
        private readonly TimeSpan absoluteExpirationRelativeToNow;
        private readonly string cacheKey;

        // For the sake of simplicity, the cache policy will only support TTL fixed time
        public CacheAttribute(string cacheKey, string absoluteExpirationRelativeToNow)
        {
            this.cacheKey = cacheKey;
            this.absoluteExpirationRelativeToNow = TimeSpan.Parse(absoluteExpirationRelativeToNow);
        }

        public override async Task InvokeAsync(AspectContext context, AsyncAspectDelegate next)
        {
            // The entire code is basically the same as if we were using MemoryCache directly
            var cache = context.ServiceProvider.GetRequiredService<IMemoryCache>();
            var r = await cache.GetOrCreateAsync(cacheKey, async e =>
            {
                await next(context); // So the actual implementation of the method logic is all in next, so just call it
                e.AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow;
                return context.ReturnValue;  Void/Task
      
        / ValueTask
      
            });
            context.ReturnValue = r; // Set ReturnValue. Since next will not be called during the cache life, ReturnValue will not have a value. We need to set the cache result to ReturnValue}}Copy the code

1.2.2 Test it out

 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!")); }}Copy the code

Results the Console

Hello World!
Hello Two!
Hello Two!
Copy the code

Plus cache Settings:

    public class TestCacheClient : ITestCacheClient{[Cache(nameof(Say), "00:00:03")]
        public string Say(string v) => v;
    }
Copy the code

Test the Console results again

Hello World!
Hello World!
Hello Two!
Copy the code

The sample code is at github.com/fs7744/AopD… A more comprehensive example of handling situations can be found at github.com/fs7744/Norn…

May you all have the pleasure of being called god nb.