Norns.urd is a lightweight AOP framework based on emit which do dynamic proxy.
It base on netstandard2.0.
The purpose of completing this framework mainly comes from the following personal wishes:
- Static AOP and dynamic AOP are implemented once
- How can an AOP framework only do dynamic proxy but can work with other DI frameworks like
Microsoft.Extensions.DependencyInjection
- How can an AOP make both sync and Async methods compatible and leave implementation options entirely to the user
Hopefully, this library will be of some useful to you
- Interceptor
- Attribute Interceptor
- Global interceptor
- Generate default implementation of Interface and Abstract Class
- InjectAttribute
- PropertyInject
- ParameterInject
- FieldInject
- FallbackAttribute
- Polly
- TimeoutAttribute
- RetryAttribute
- CircuitBreakerAttribute
- BulkheadAttribute
- CacheAttribute (support Multistage cache with memory cache and distributed cache)
This is simple demo whch to do global interceptor, full code fot the demo you can see Examples.WebApi
-
create ConsoleInterceptor.cs
using Norns.Urd; using Norns.Urd.Reflection; using System; using System.Threading.Tasks; namespace Examples.WebApi { public class ConsoleInterceptor : AbstractInterceptor { public override async Task InvokeAsync(AspectContext context, AsyncAspectDelegate next) { Console.WriteLine($"{context.Service.GetType().GetReflector().FullDisplayName}.{context.Method.GetReflector().DisplayName}"); await next(context); } } }
-
set WeatherForecastController's method be virtual
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { [HttpGet] public virtual IEnumerable<WeatherForecast> Get() => test.Get(); }
-
AddControllersAsServices
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddControllersAsServices(); }
-
add GlobalInterceptor to di
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddControllersAsServices(); services.ConfigureAop(i => i.GlobalInterceptors.Add(new ConsoleInterceptor())); }
-
run
you will see this in console
Norns.Urd.DynamicProxy.Generated.WeatherForecastController_Proxy_Inherit.IEnumerable<WeatherForecast> Get()
- AOP
- Polly
- Cache
- HttpClient
- Trace
- Runtime Metrics collect
Just simple benchmark test, and does not represent the whole scenario
Castle and AspectCore are excellent libraries,
Many implementations of Norns.urd refer to the source code of Castle and AspectCore.
BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19044.1288/21H2/November2021Update)
Intel Core i7-10700 CPU 2.90GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.402
[Host] : .NET 6.0.10 (6.0.1022.47605), X64 RyuJIT AVX2
DefaultJob : .NET 6.0.10 (6.0.1022.47605), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev | Gen0 | Allocated |
|----------------------------------------------- |----------:|---------:|---------:|-------:|----------:|
| TransientInstanceCallSyncMethodWhenNoAop | 52.41 ns | 0.319 ns | 0.298 ns | 0.0134 | 112 B |
| TransientInstanceCallSyncMethodWhenNornsUrd | 120.26 ns | 0.237 ns | 0.185 ns | 0.0410 | 344 B |
| TransientInstanceCallSyncMethodWhenCastle | 168.58 ns | 0.842 ns | 0.788 ns | 0.0610 | 512 B |
| TransientInstanceCallSyncMethodWhenAspectCore | 439.43 ns | 1.466 ns | 1.225 ns | 0.0772 | 648 B |
| TransientInstanceCallAsyncMethodWhenNoAop | 88.63 ns | 0.318 ns | 0.282 ns | 0.0305 | 256 B |
| TransientInstanceCallAsyncMethodWhenNornsUrd | 211.48 ns | 1.315 ns | 1.098 ns | 0.0668 | 560 B |
| TransientInstanceCallAsyncMethodWhenCastle | 197.95 ns | 0.657 ns | 0.549 ns | 0.0782 | 656 B |
| TransientInstanceCallAsyncMethodWhenAspectCore | 522.63 ns | 4.313 ns | 4.034 ns | 0.1030 | 864 B |
## License
[MIT](https://github.com/fs7744/Norns.Urd/blob/main/LICENSE)