1

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.

0

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

4 Comments

But in this case, with the Reflection.Emit, I would have to somehow "inject/override" all methods with the attribute at runtime, before using them, right?
@Guilherme Yes, all the methods would have to be virtual, you would create a new derived class, and override all the methods. In each override you could call some other code before calling the base method. You then instantiate the generated derived class and use it instead of the original.
@Guilherme I have some sample code that does this, I can post it but not until tomorrow, if you think it might be useful
Thank you, I'll study a little bit more the Reflection.Emit, but I am not sure if i'll use this approach. I will take a look at NInject too.
1

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

Comments

1

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.