Guilherme Holtz
Guilherme Holtz

Reputation: 485

Trigger a method before other method execution

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 time, they are before methods that take too long to execute.

Upvotes: 1

Views: 2840

Answers (3)

JuanR
JuanR

Reputation: 7783

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.

Upvotes: 1

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249606

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.

Upvotes: 1

nvoigt
nvoigt

Reputation: 77304

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).

Upvotes: 1

Related Questions