pamidur / aspect-injector

AOP framework for .NET (c#, vb, etc)
Apache License 2.0
742 stars 111 forks source link

Aspect attributes are not triggered on interface methods #177

Closed selcukkutuk closed 2 years ago

selcukkutuk commented 2 years ago

First of all, thank you very much for this wonderful library. I have a problem in the example usage scenario below. When I use attribute in interface method it is not triggered. Is there a situation that prevents this in terms of design or is there something that I have overlooked? Thank you very much for your answer in advance.

[Aspect(Scope.Global)]
[Injection(typeof(LogAspectAttribute))]
public class LogAspectAttribute : Attribute
{
    [Advice(Kind.Around, Targets = Target.Method)]
    public object HandleMethod(
        [Argument(Source.Name)] string name,
        [Argument(Source.Arguments)] object[] arguments,
        [Argument(Source.Target)] Func<object[], object> method)
    {
        Console.WriteLine($"Executing method {name}");
        var result = method(arguments);

        Console.WriteLine($"Executed method {name}");

        return result;
    }
}

public class SampleService : ISampleService
{
    public void WriteMessage(string message)
    {
        Console.WriteLine(message);
    }
}

public interface ISampleService
{
    [LogAspect]
    void WriteMessage(string message);
}
pamidur commented 2 years ago

Hi @selcukkutuk , Unfortunately per member interface trigger/injection is not (yet?) implemented. But interfaces can be used as triggers instead of attributes. Sometimes it isn't convenient and you might need to apply additional filters so your aspect acts on specific methods only, but in general it should work for you.

[Aspect(Scope.Global)]
[Injection(typeof(LogAspectAttribute))]
public class LogAspectAttribute : Attribute
{
    [Advice(Kind.Around, Targets = Target.Method)]
    public object HandleMethod(
        [Argument(Source.Name)] string name,
        [Argument(Source.Arguments)] object[] arguments,
        [Argument(Source.Target)] Func<object[], object> method)
    {
        Console.WriteLine($"Executing method {name}");
        var result = method(arguments);

        Console.WriteLine($"Executed method {name}");

        return result;
    }
}

public class SampleService : ISampleService
{
    public void WriteMessage(string message)
    {
        Console.WriteLine(message);
    }
}

[Injection(typeof(LogAspectAttribute))]
public interface ISampleService
{
    void WriteMessage(string message);
}
selcukkutuk commented 2 years ago

Hi @pamidur , First of all, thank you very much for your answer. I would appreciate if you could explain with an example what kind of filter I should apply in the "you may need to apply additional filters" section.

pamidur commented 2 years ago

The easiest would be

[Injection(typeof(LogAspectAttribute), Propagation = PropagateTo.Methods, PropagationFilter = nameof(ISampleService.WriteMessage))]
public interface ISampleService
{
    void WriteMessage(string message);
}

the other way is to request

[Argument(Source.Metadata)] MethodBase metadata,

and then check in runtime if method belongs to the interface

selcukkutuk commented 2 years ago

@pamidur Thank you very much for your support.👍🏻