1

我想为像 Logging 、 Exception 等横切关注点提供这样的属性...

public class MyService
{

[Log] // Interception (AOP)
[ExceptionHandler] // Interception (AOP)
public void DoSomething()
   {

   }
}

我知道我可以用 postsharp 编写这些代码,但我想用 Castle Core 和 ...

任何人都可以帮助我并为此目的编写示例吗???我需要一个非常简单的示例来学习概念

4

4 回答 4

3

Autofac 是一个免费的 IoC 容器。我将 Autofac 与 Autofac.Extras.DynamicProxy2 nugetdocs一起使用。

假设您知道为什么以及何时(而不是)使用拦截器,并且您想要拦截一些功能:

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() 以与封闭类进行通信。我对此不是 100% 满意,因此其他人的一些评论会有所帮助)

然后,以日志记录为例:

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();
}
于 2015-04-22T02:31:40.003 回答
1

Java 有 AOP 和 aspectJ 和编织(LTW 加载时间和代理,编译时间 CTW) C#(城堡)有拦截器,也使用(动态)代理。您可以将其视为 LTW 变体。

我在 c# 中使用了这个设置。这不是什么大魔法,而且代码也很有限。

Autofac 5.1.0
Autofac.Extras.DynamicProxy 5.0.0
Castle.Core 4.4.0

诀窍是

  1. 定义一些属性,用作拦截器属性
  2. 定义一个拦截器,检查被调用方法的属性
  3. 使用方法和接口方法上的属性定义接口
  4. 定义接口的实现类
  5. 使用 autofac 注册整个设置
  6. 测试/运行/开始

1)定义一些属性

using System;
[AttributeUsage(
AttributeTargets.Method,
AllowMultiple = true)]

public class SomeAttribute : Attribute
{
    public long Id { get; set; }
}

2)定义一个城堡动态拦截器(又名代理)

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) test/run/go :运行整个设置:

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 invocation.Proceed() 时对其进行编码:

@前

做一点事(){...}

@后

于 2020-03-16T17:07:39.333 回答
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);
     }
 }
于 2020-12-11T05:01:24.707 回答
0

这个库满足你的需要https://github.com/pamidur/aspect-injector

[LogCall]
public void Calculate() 
{ 
    Console.WriteLine("Calculated");
}

附言。无耻的自我广告

于 2020-10-16T12:18:35.907 回答