Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Core: attributes that execute before and after method

Tags:

c#

.net-core

In Java, it is possible to use AspectJ for adding behavior before and after executing a method, using method annotations. Since C# Attributes seem to be very similar, I was wondering whether it would be possible to achieve similar behavior. I was looking in several tutorials and other sources (1, 2, 3), but none of them helped me.

I thought that maybe I could be able to mimic the behavior by inserting the code into Attribute constructor and making it disposable, like this:

[AttributeUsage(AttributeTargets.Method)]
public class MyWritingAttribute : Attribute, IDisposable
{
    public MyWritingAttribute()
    {
        Console.WriteLine("Attribute created");
    }

    public void Dispose()
    {
        Console.WriteLine("Attribute disposed");
    }
}

However, when using the attribute like this, only Hello world! got displayed in the console:

class Program
{
    static void Main(string[] args)
    {
        SayHelloWorld();
        Console.ReadLine();
    }

    [MyWriting]
    private static void SayHelloWorld()
    {
        Console.WriteLine("Hello World!");
    }
}

I was thinking that maybe Console is not reachable in the attribute, but even when replacing it with throw new Exception() expressions, no exception was thrown. How is it possible that StringLengthAttribute from EF works, but my attribute is not even instantiated? And how do I make the attribute run before and after the decorated method?

like image 685
lss Avatar asked Sep 01 '17 12:09

lss


2 Answers

You need some framework that is able to handle your attribute appropriately. Only because the attribute exists doesn´t mean it will have any affect.

I wrote some easy engine that does that. It will determine if the attribute is present on the passed action and if so get the reflected methods in order to execute them.

class Engine
{
    public void Execute(Action action)
    {
        var attr = action.Method.GetCustomAttributes(typeof(MyAttribute), true).First() as MyAttribute;
        var method1 = action.Target.GetType().GetMethod(attr.PreAction);
        var method2 = action.Target.GetType().GetMethod(attr.PostAction);

        // now first invoke the pre-action method
        method1.Invoke(null, null);
        // the actual action
        action();
        // the post-action
        method2.Invoke(null, null);
    }
}
public class MyAttribute : Attribute
{
    public string PreAction;
    public string PostAction;
}

Of course you need some null-ckecks, e.g. in the case the methods don´t exist or aren´t static.

Now you have to decorate your action with the attribute:

class MyClass
{
    [MyAttribute(PreAction = "Handler1", PostAction = "Handler2")]
    public void DoSomething()
    {
        
    }

    public static void Handler1()
    {
        Console.WriteLine("Pre");
    }
    public static void Handler2()
    {
        Console.WriteLine("Post");
    }
}

Finally you can execute that method within our engine:

var engine = new Engine();
var m = new MyClass();
engine.Execute(m.DoSomething);
like image 111
MakePeaceGreatAgain Avatar answered Oct 12 '22 19:10

MakePeaceGreatAgain


Just like with Java and AspectJ, you need separate AoP tooling to inject code like this in .NET.

PostSharp is one such tool, probably the best known. I belive they have support for .NET core since version 5.

like image 38
Anders Forsgren Avatar answered Oct 12 '22 19:10

Anders Forsgren