Trigger a method before other method execution

Guilherme Source

Is there a way to call a method to be executed before another method, like a trigger?

Something like an attribute that indicates the method to be executed, like this:

[OnBefore(MethodToBeExecutedBefore)]
public void MethodExecutedNormally()
{
    //method code
}

I have a situation that I need to call a check method very often and most of the times are before methods that take to long to execute.

c#asp.netasp.net-mvc

Answers

answered 5 months ago Titian Cernicova-Dragomir #1

There is no built in way to achieve this result, if you are using a dependency injection mechanism you can use the interception facilities if the DI framework supports this. (Ex: Unity, NInject)

If you want to go low level you can also use Reflection.Emit to create a derived class at runtime, that overrides methods with a particular attribute that invokes any extra functionality you want, but that is more difficult.

answered 5 months ago nvoigt #2

What you are talking about is called AOP or Aspect Oriented Programming.

There are no built-in options in C#. While Attributes exists, there is no mechanism to take any actions with them. You always need a piece of code that reads those attributes and then does something. Attributes themselves are only metadata and markers.

As far as external tools go, Postsharp is the de-facto standard AOP postcompiler for .NET, but it's not free (at least not for real use, there is a free version you may want to try, maybe it's enough for your use-case).

answered 5 months ago JuanR #3

I think you should consider an event driven approach.

You could create an interface and some base classes to handle the event, then have your long running classes inherit from it. Subscribe to the event and handle accordingly:

public delegate void BeforeMethodExecutionHandler<TArgs>(ILongRunningWithEvents<TArgs> sender, TArgs args, string caller);
public interface ILongRunningWithEvents<TArgs>
{
    event BeforeMethodExecutionHandler<TArgs> OnBeforeMethodExecution;
}

public class LongRunningClass<TArgs> : ILongRunningWithEvents<TArgs>
{
    private BeforeMethodExecutionHandler<TArgs> _onBeforeMethodExecution;
    public event BeforeMethodExecutionHandler<TArgs> OnBeforeMethodExecution
    {
        add { _onBeforeMethodExecution += value; }
        remove { _onBeforeMethodExecution -= value; }
    }   
    protected void RaiseOnBeforeMethodExecution(TArgs e, [CallerMemberName] string caller = null)
    {
        _onBeforeMethodExecution?.Invoke(this, e, caller);
    }
}

public class ConcreteRunningClass : LongRunningClass<SampleArgs>
{
    public void SomeLongRunningMethod()
    {
        RaiseOnBeforeMethodExecution(new SampleArgs("Starting!"));
        //Code for the method here
    }
}

public class SampleArgs
{
    public SampleArgs(string message)
    {
        Message = message;
    }

    public string Message { get; private set; }
}

Sample usage:

 public static void TestLongRunning()
 {
     ConcreteRunningClass concrete = new ConcreteRunningClass();
     concrete.OnBeforeMethodExecution += Concrete_OnBeforeMethodExecution;
     concrete.SomeLongRunningMethod();
 }

 private static void Concrete_OnBeforeMethodExecution(ILongRunningWithEvents<SampleArgs> sender, SampleArgs args, string caller)
{
    Console.WriteLine("{0}: {1}", caller ?? "unknown", args.Message);
}

The message SomeLongRunningMethod: Starting! will be output before the long-running method executes.

You could add the caller name to the args. I whipped this out real quick to illustrate.

UPDATE: I see you added tags for ASP.NET MVC. The concept still applies to controllers as controllers are just classes.

comments powered by Disqus