How to Intercept a Method Call in C#

How do I intercept a method call in C#?

C# is not an AOP oriented language. It has some AOP features and you can emulate some others but making AOP with C# is painful.

I looked up for ways to do exactly what you wanted to do and I found no easy way to do it.

As I understand it, this is what you want to do:

[Log()]
public void Method1(String name, Int32 value);

and in order to do that you have two main options

  1. Inherit your class from MarshalByRefObject or ContextBoundObject and define an attribute which inherits from IMessageSink. This article has a good example. You have to consider nontheless that using a MarshalByRefObject the performance will go down like hell, and I mean it, I'm talking about a 10x performance lost so think carefully before trying that.

  2. The other option is to inject code directly. In runtime, meaning you'll have to use reflection to "read" every class, get its attributes and inject the appropiate call (and for that matter I think you couldn't use the Reflection.Emit method as I think Reflection.Emit wouldn't allow you to insert new code inside an already existing method). At design time this will mean creating an extension to the CLR compiler which I have honestly no idea on how it's done.

The final option is using an IoC framework. Maybe it's not the perfect solution as most IoC frameworks works by defining entry points which allow methods to be hooked but, depending on what you want to achive, that might be a fair aproximation.

Method Interception using Reflection in C#

Could something like this work for what you need?

[AttributeUsage(AttributeTargets.Field)]
public class TrackedField : Attribute { }

public class ATrackedObject
{
public ATrackedObject()
{
Type objType = this.GetType();
foreach (FieldInfo f in objType.GetFields())
{
if (f.IsDefined(typeof(TrackedField), false)) {
if (f.FieldType == typeof(Action))
{
var currentValue = f.GetValue(this) as Action;
Action newValue = () =>
{
Console.WriteLine($"Tracking {f.Name}");
currentValue.Invoke();
};

f.SetValue(this, newValue);
}
}
}
}

[TrackedField]
public Action SomeMethod = () => Console.WriteLine("Some Method Called");
}

this is done with a simple Action property but it could be extended to use Func<>

edit: forgot to include usage and output.

usage:

static void Main(string[] args)
{
var obj = new ATrackedObject();
obj.SomeMethod();

Console.Read();
}

output:

Tracking SomeMethod
Some Method Called

Intercepting method calls in C# using Proxies

C# designers have never been in favor of AOP, there's no easy way to intercept method calls without using Proxies and Marshaling, which have their own drawbacks!
In case anyone wants to intercept method/property calls (eg. cross cutting concerns), I've found RealProxy to be of some help.

RealProxy From MSDN:

A client that uses an object across any kind of a remoting boundary is
actually using a transparent proxy for the object. The transparent
proxy provides the illusion that the actual object resides in the
client's space. It achieves this by forwarding calls made on it to the
real object using the remoting infrastructure.

Note: A type being proxied using RealProxy must be either an interface or inherit from MarshalByRefObject.

Here's some implementation of RealProxy using a Factory Method to create a proxy of an object at runtime:

public abstract class RuntimeProxy
{
public static readonly object Default = new object();

public static Target Create<Target>(Target instance, RuntimeProxyInterceptor interceptor) where Target : class
{
return (Target)new InternalProxy<Target>(instance, interceptor).GetTransparentProxy();
}

public static Target Create<Target>(Target instance, Func<RuntimeProxyInvoker, object> factory) where Target : class
{
return (Target)new InternalProxy<Target>(instance, new InternalRuntimeProxyInterceptor(factory)).GetTransparentProxy();
}


class InternalProxy<Target> : RealProxy where Target : class
{
readonly object Instance;
readonly RuntimeProxyInterceptor Interceptor;

public InternalProxy(Target instance, RuntimeProxyInterceptor interceptor)
: base(typeof(Target))
{
Instance = instance;
Interceptor = interceptor;
}

public override IMessage Invoke(IMessage msg)
{
var methodCall = (IMethodCallMessage)msg;
var method = (MethodInfo)methodCall.MethodBase;

try
{
var result = Interceptor.Invoke(new InternalRuntimeProxyInterceptorInvoker(Instance, method, methodCall.InArgs));

if (result == RuntimeProxy.Default)
result = method.ReturnType.IsPrimitive ? Activator.CreateInstance(method.ReturnType) : null;

return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (Exception ex)
{
if (ex is TargetInvocationException && ex.InnerException != null)
return new ReturnMessage(ex.InnerException, msg as IMethodCallMessage);

return new ReturnMessage(ex, msg as IMethodCallMessage);
}
}
}

class InternalRuntimeProxyInterceptor : RuntimeProxyInterceptor
{
readonly Func<RuntimeProxyInvoker, object> Factory;

public InternalRuntimeProxyInterceptor(Func<RuntimeProxyInvoker, object> factory)
{
this.Factory = factory;
}

public override object Invoke(RuntimeProxyInvoker invoker)
{
return Factory(invoker);
}
}

class InternalRuntimeProxyInterceptorInvoker : RuntimeProxyInvoker
{
public InternalRuntimeProxyInterceptorInvoker(object target, MethodInfo method, object[] args)
: base(target, method, args)
{ }
}
}

public abstract class RuntimeProxyInterceptor
{
public virtual object Invoke(RuntimeProxyInvoker invoker)
{
return invoker.Invoke();
}
}

public abstract class RuntimeProxyInvoker
{
public readonly object Target;
public readonly MethodInfo Method;
public readonly ReadOnlyCollection<object> Arguments;

public RuntimeProxyInvoker(object target, MethodInfo method, object[] args)
{
this.Target = target;
this.Method = method;
this.Arguments = new ReadOnlyCollection<object>(args);
}

public object Invoke()
{
return Invoke(this.Target);
}

public object Invoke(object target)
{
if (target == null)
throw new ArgumentNullException("target");

try
{
return this.Method.Invoke(target, this.Arguments.ToArray());
}
catch (TargetInvocationException ex)
{
throw ex.InnerException;
}
}
}

You can use the RuntimeProxy as a factory to create a proxy of an object and intercept all method/property calls and invoke the actual method.

Here's a sample:

class SomeClass : MarshalByRefObject
{
public int Mul(int a, int b)
{
return a * b;
}

public void SetValue(int val)
{
this.Val = val;
}

public int Val { get; set; }
}

Use RuntimeProxy class to create a proxy for an instance of the SomeClass class and intercept the calls:

var test = new SomeClass();
var proxy = RuntimeProxy.Create(test, t =>
{
// cross-cut here

return t.Invoke(); // invoke the actual call
});

var res = proxy.Mul(3, 4); // method with return value
proxy.SetValue(2); // void method, setting some property
var val = proxy.Val; // property access

You could use interface types in case you don't want to inherit from MarshalByRefObject class.

How to intercept method calls in C#

I wouldn't use inheritance - you can use composition here. Create your own class which has the same methods - or in fact only the ones you're interested in - and delegate through that. That way you can be sure you won't "miss" any methods accidentally, because anything you don't implement won't be callable through the rest of your codebase... so long as you make sure the rest of your code doesn't refer to the original library class, of course.

C# Moq Intercept method call

You are trying to mock an interface and verify an implementation of this interface.

You could make methods C and D virtual and use the implementation in the mock.

Implementation:

public class ObjectImplementation : IObject
{
public void MethodA(ObjectA arg1)
{
if (arg1.Something)
{
MethodB(new ObjectB(arg1), new ObjectC(arg1));
}
else
{
MethodC(new ObjectD(arg1), new ObjectE(arg1));
}
}

public virtual void MethodB(ObjectB arg1, ObjectC arg2)
{

}

public virtual void MethodC(ObjectD arg1, ObjectE arg2)
{

}
}

Test:

[Fact]
public void Test_WhenSomethingIsTrue_MethodB_Invoked_WithObjects_B_And_C()
{
// Arrange
Mock<ObjectImplementation> mockObject = new Mock<ObjectImplementation>();
ObjectA arg = new ObjectA();
arg.Something = true;

// Act
mockObject.Object.MethodA(arg);

// Assert
mockObject.Verify(o => o.MethodB(It.Is<ObjectB>(b=> b.Arg == arg), It.Is<ObjectC>(c => c.Arg == arg)));
}

[Fact]
public void Test_WhenSomethingIsFalse_MethodC_Invoked_WithObjects_D_And_E()
{
// Arrange
Mock<ObjectImplementation> mockObject = new Mock<ObjectImplementation>();
ObjectA arg = new ObjectA();
arg.Something = false;

// Act
mockObject.Object.MethodA(arg);

// Assert
mockObject.Verify(o => o.MethodC(It.Is<ObjectD>(d => d.Arg == arg), It.Is<ObjectE>(e => e.Arg == arg)));
}

Intercept Method/Property call in c#

You could create a proxy for Foo that could be mocked:

public class FooProxy : IFoo
{
private Foo _Foo;
public FooProxy(Foo foo)
{
_Foo = foo;
}
public int FooValue
{
get {return _Foo.FooValue();
}
}

public interface IFoo
{
public int FooValue {get;}
}

then you can use DI to "inject" an IFoo and make your code more testable.



Related Topics



Leave a reply



Submit