Skip to content

fs7744/Norns

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Norns

中文文档

Goal

This a project to do static weaving and dynamic weaving.

Desgin

AOP base on proxy

  1. Generate proxy class type
  2. Replace type to proxy type for di
  3. Do aop in proxy class

Static weaving generate code base on roslyn

There is two way that we will try to support :

AOT (Norns.Skuld)

experimental feature

(ps: because source-generators not allow loading referenced assemblies now, so can't share package to other now. I will try to find way to fix this.)

JIT (Norns.Verthandi)

  • use Reflection to generator proxy class code
  • use roslyn sdk to convert code to type
Not use this in production.

Roslyn is so great, but if we just use it once before di, it seem wasting a lot of memory and cpu.

Actually we can do jit after generate dll to generate proxy dll, make the jit to aot after build.

But now there is source-generators.

Dynamic weaving Emit (Norns.Urd)

  • Emit to generate proxy type

(ps: this will begin after static weaving done)

How to use

JIT (Norns.Verthandi)

  1. reference Norns.Adapters.DependencyInjection

  2. write InterceptorGenerator base on AbstractInterceptorGenerator

using Norns.Destiny.Structure;
using Norns.Destiny.AOP;
using Norns.Destiny.AOP.Notations;
using Norns.Destiny.Notations;
using System.Collections.Generic;
using System.Linq;

namespace Norns.Benchmark
{
    public class ConsoleCallMethodGenerator : AbstractInterceptorGenerator
    {
        public override IEnumerable<INotation> BeforeMethod(ProxyGeneratorContext context, IMethodSymbolInfo method)
        {
            typeof(System.Console).Name.ToString(); // just make sure load System.Console dll before jit generate code
            if (!method.Parameters.IsEmpty)
            {
                yield return $"System.Console.WriteLine($\"Call Method {method.Name} at {{System.DateTime.Now.ToString(\"yyyy-MM-dd HH:mm:ss.fff\")}} {method.Parameters.First().Type.FullName} {method.Parameters.First().Name} = {{{method.Parameters.First().Name}}}".ToNotation();
                foreach (var item in method.Parameters.Skip(1))
                {
                    yield return $", {item.FullName} {item.Name} = {{{item.Name}}}".ToNotation();
                }
                yield return "\");".ToNotation();
            }
        }

        public override IEnumerable<INotation> AfterMethod(ProxyGeneratorContext context, IMethodSymbolInfo method)
        {
            if (method.HasReturnValue)
            {
                yield return $"System.Console.WriteLine($\"return {{{context.GetReturnValueParameterName()}}} at {{System.DateTime.Now.ToString(\"yyyy-MM-dd HH:mm:ss.fff\")}}\");".ToNotation();
            }
        }
    }
}
  1. write interface
using System;

namespace Norns.Benchmark
{
    public interface IC
    {
        int AddOne(int v);

        public int AddOne2(int v)
        {
            return v + 1;
        }
    }
}
  1. write class
public class C : IC
{
    public int AddOne(int v)
    {
        return v;
    }
}
  1. set to DI

if use asp.net core, just use UseVerthandiAop like :

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
        .UseVerthandiAop(new IInterceptorGenerator[] { new ConsoleCallMethodGenerator() })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

if not, you can try this :

internal class Program
{
    private static void Main(string[] args)
    {
        var p = new ServiceCollection()
            .AddTransient<IC, C>()
            .BuildVerthandiAopServiceProvider(new IInterceptorGenerator[] { new ConsoleCallMethodGenerator() })
            .GetRequiredService<IC>();

        var result = p.AddOne(99);
        Console.WriteLine($"p.AddOne(99) 's result is {result}.");
        Console.WriteLine();
        result = p.AddOne2(1);
        Console.WriteLine($"p.AddOne2(1) 's result is {result}.");

        Console.ReadKey();
    }
}

result :

Call Method AddOne at 2020-07-05 15:42:21.999 int v = 99
return 99 at 2020-07-05 15:42:22.002
p.AddOne(99) 's result is 99.

Call Method AddOne2 at 2020-07-05 15:42:22.003 int v = 1
return 2 at 2020-07-05 15:42:22.003
p.AddOne2(1) 's result is 2.

AOT (Norns.Skuld)

There is Noting until source-generators can do this.

Because source-generators not allow loading referenced assemblies now, so can't share package to other, and i don't want to write the demo.

Emit (Norns.Urd)

waiting to start

Plan

About

dotnet core aop static weaving on roslyn

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages