我希望像Logging,Exception等一样具有这样的属性:
public class MyService
{
[Log] // Interception (AOP)
[ExceptionHandler] // Interception (AOP)
public void DoSomething()
{
}
}
我知道我可以用postsharp编写这些代码,但我想用Castle Core等免费库编写这些拦截...
任何人都可以帮助我并为此目的写一个样本吗? 我需要一个非常简单的学习概念样本
答案 0 :(得分:3)
Autofac是一个免费的IoC容器。我将Autofac与Autofac.Extras.DynamicProxy2 nuget,docs一起使用。
假设您知道为什么以及何时(而不是)使用拦截器,并且您想拦截某些功能:
public class FooService : IFooService
{
public void MoreFoo()
{
DoSomething();
}
public void LessFoo()
{
DoSomethingElse();
}
}
需要“有线”。我喜欢属性,因为您不需要在IoC容器布线中明确指定拦截器。您只需指定要注意的属性:
[Intercept(typeof(Logger)]
public class FooService : IFooService { ... }
并连线:
var builder = new ContainerBuilder();
builder.RegisterType<FooService>()
.EnableClassInterceptors();
然后在另一个文件中创建Logger拦截器:
class Logger : IInterceptor
{
public void Intercept(IInvocation invocation) // implements the IInterceptor interface
{
_loggerService.Log("calling " + invocation.Method.Name);
invocation.Proceed();
_loggerService.Log("finished " + invocation.Method.Name);
}
}
如您所见,您可以创建计时器,try-catch块等等。数据库环境和其他可支配资源是一个有趣的:
class Logger : IInterceptor
{
public void Intercept(IInvocation invocation) // implements the IInterceptor interface
{
using (var someThing = new SomeResource())
{
invocation.Proceed();
}
}
}
通常使用这样的资源,您需要在方法中使用someThing。这是另一个问题的主题! (请参阅invocation.SetArgumentValue或invocation.TargetType.GetProperties()以与封闭类进行通信。我对此并不是很满意,因此其他人的一些评论会有所帮助)
然后,以日志记录为例:
void ManageFoo()
{
// sorry for the messy code, what else can I do?!
_logger("more foo please");
_fooService.MoreFoo();
_logger("less foo please");
_fooService.LessFoo();
_logger("enough foo");
}
ManageFoo方法的实际问题在所有日志记录中都丢失了(添加安全性和其他问题,最终可能会造成很大的混乱)。
现在你可以像这样重写它:
void ManageFoo()
{
_fooService.MoreFoo();
_fooService.LessFoo();
}
答案 1 :(得分:1)
Java具有使用AspectJ和编织的AOP(具有代理的LTW加载时间,以及CTW的编译时间) C#(城堡)具有拦截器,也使用(动态)代理。您可以将其视为LTW变体。
我在c#中使用了此设置。 这不是什么大魔术,而且代码也很有限。
Autofac 5.1.0
Autofac.Extras.DynamicProxy 5.0.0
Castle.Core 4.4.0
诀窍是
1)定义一些服饰
using System;
[AttributeUsage(
AttributeTargets.Method,
AllowMultiple = true)]
public class SomeAttribute : Attribute
{
public long Id { get; set; }
}
2)定义Castle动态拦截器(也称为代理)
using Castle.DynamicProxy;
using System;
public class SomeInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (Attribute.IsDefined(invocation.Method, typeof(SomeAttribute)))
{
Console.Write("Method called: " + invocation.Method.Name);
}
invocation.Proceed();
}
}
现在,使用接口创建对象(不要忘记,将属性放在接口上,而不是在impl上!)
3)定义接口
public interface AOPTest
{
[Some(Id = 10)]
void DoSomething();
}
4)定义实现:
public class AOPTestImpl : AOPTest
{
public void DoSomething()
{
}
}
5)用autofac注册整个设置
builder.RegisterType<AOPTestImpl>()
.As<AOPTest>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(SomeInterceptor));
builder.RegisterType<SomeInterceptor>().AsSelf();
6)测试/运行/运行:运行整个设置:
using Autofac;
using Autofac.Extras.DynamicProxy;
using (var scope = bootstrap.BootStrap.Container.BeginLifetimeScope())
{
var aOPTest = scope.Resolve<AOPTest>();
aOPTest.DoSomething();
}
我不知道它是如何工作的,但是这个想法是:
界面->代理->实现 因此,如果您通过接口调用实现,则代理/拦截器介于两者之间。
注意:如果在doSomething()方法内调用其他也需要拦截的代码,则可能需要一个autofac类拦截器EnableClassInterceptors
注意:这不是世界上最快的解决方案。某些过滤器拦截器可能更快,而像Fody或PostSharp这样的编译时间编织可能更快。但这会很多次。
注意:如果需要在方法开始之前完成某些操作,请在调用之前对它进行编码。Proceed();如果您需要在最后完成某件事,请在调用@ After.Proceed()之后进行编码:
@之前
DoSomething(){...}
@之后
答案 2 :(得分:0)
此库可以满足您的需求https://github.com/pamidur/aspect-injector
[LogCall]
public void Calculate()
{
Console.WriteLine("Calculated");
}
ps。无耻的自我广告
答案 3 :(得分:0)
如果要使用运行时aop,可以尝试https://fs7744.github.io/Norns.Urd/index.html
这非常简单,就像一个拦截器:
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);
}
}