https://github.com/fs7744/Norns
dotnet core aop static weaving on roslyn
https://github.com/fs7744/Norns
aop aspect netcore roslyn
Last synced: about 1 year ago
JSON representation
dotnet core aop static weaving on roslyn
- Host: GitHub
- URL: https://github.com/fs7744/Norns
- Owner: fs7744
- License: mit
- Created: 2018-10-28T02:40:56.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2020-10-24T06:45:58.000Z (over 5 years ago)
- Last Synced: 2024-11-13T04:52:59.801Z (over 1 year ago)
- Topics: aop, aspect, netcore, roslyn
- Language: C#
- Homepage:
- Size: 576 KB
- Stars: 23
- Watchers: 3
- Forks: 5
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Norns
[中文文档](doc/zh/README.md)
## Goal
This a project to do static weaving and dynamic weaving.
## Desgin
### AOP base on proxy
0. Generate proxy class type
1. Replace type to proxy type for di
2. Do aop in proxy class
### Static weaving generate code base on [roslyn](https://github.com/dotnet/roslyn)
There is two way that we will try to support :
#### AOT (Norns.Skuld)
> experimental feature
* use [source-generators](https://github.com/dotnet/roslyn/blob/master/docs/features/source-generators.md) to generator proxy class code
`
(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)
0. reference `Norns.Adapters.DependencyInjection`
1. write InterceptorGenerator base on `AbstractInterceptorGenerator`
```csharp
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 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 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();
}
}
}
}
```
2. write interface
```csharp
using System;
namespace Norns.Benchmark
{
public interface IC
{
int AddOne(int v);
public int AddOne2(int v)
{
return v + 1;
}
}
}
```
3. write class
```csharp
public class C : IC
{
public int AddOne(int v)
{
return v;
}
}
```
4. set to DI
if use asp.net core, just use `UseVerthandiAop` like :
```csharp
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();
});
}
```
if not, you can try this :
```csharp
internal class Program
{
private static void Main(string[] args)
{
var p = new ServiceCollection()
.AddTransient()
.BuildVerthandiAopServiceProvider(new IInterceptorGenerator[] { new ConsoleCallMethodGenerator() })
.GetRequiredService();
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 :
```shell
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
- [ ] [Norns-JIT-Imporve](https://github.com/fs7744/Norns/projects/1)