Skip to content

Commit ce03d98

Browse files
committed
Renewing bugfix in PR #92
1 parent e5a2707 commit ce03d98

File tree

5 files changed

+156
-2
lines changed

5 files changed

+156
-2
lines changed

src/Interceptors/InstanceInterceptors/InterfaceInterception/InterfaceMethodOverride.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,17 @@ private MethodBuilder CreateMethodOverride(MethodBuilder delegateMethod)
414414
il.Emit(OpCodes.Ceq);
415415
il.Emit(OpCodes.Brtrue_S, noException);
416416
il.Emit(OpCodes.Ldloc, ex);
417-
il.Emit(OpCodes.Throw);
417+
418+
if (ReflectionHelper.ExceptionDispatchInfoCaptureMethod != null
419+
&& ReflectionHelper.ExceptionDispatchInfoThrowMethod != null)
420+
{
421+
il.EmitCall(OpCodes.Call, ReflectionHelper.ExceptionDispatchInfoCaptureMethod, null);
422+
il.EmitCall(OpCodes.Callvirt, ReflectionHelper.ExceptionDispatchInfoThrowMethod, null);
423+
}
424+
else
425+
{
426+
il.Emit(OpCodes.Throw);
427+
}
418428

419429
il.MarkLabel(noException);
420430

src/Interceptors/TypeInterceptors/VirtualMethodInterception/InterceptingClassGeneration/MethodOverride.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,17 @@ private MethodBuilder CreateMethodOverride(MethodBuilder delegateMethod)
416416
il.Emit(OpCodes.Ceq);
417417
il.Emit(OpCodes.Brtrue_S, noException);
418418
il.Emit(OpCodes.Ldloc, ex);
419-
il.Emit(OpCodes.Throw);
419+
420+
if (ReflectionHelper.ExceptionDispatchInfoCaptureMethod != null
421+
&& ReflectionHelper.ExceptionDispatchInfoThrowMethod != null)
422+
{
423+
il.EmitCall(OpCodes.Call, ReflectionHelper.ExceptionDispatchInfoCaptureMethod, null);
424+
il.EmitCall(OpCodes.Callvirt, ReflectionHelper.ExceptionDispatchInfoThrowMethod, null);
425+
}
426+
else
427+
{
428+
il.Emit(OpCodes.Throw);
429+
}
420430

421431
il.MarkLabel(noException);
422432

src/Utilities/ReflectionHelper.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,5 +149,21 @@ public static TAttribute[] GetAllAttributes<TAttribute>(MemberInfo member, bool
149149
attributes.AddRange(GetAttributes<TAttribute>(member, inherits));
150150
return attributes.ToArray();
151151
}
152+
153+
public static readonly MethodInfo ExceptionDispatchInfoCaptureMethod;
154+
155+
public static readonly MethodInfo ExceptionDispatchInfoThrowMethod;
156+
157+
static ReflectionHelper()
158+
{
159+
Assembly mscorlib = typeof(int).Assembly;
160+
ExceptionDispatchInfoCaptureMethod = mscorlib
161+
?.GetType("System.Runtime.ExceptionServices.ExceptionDispatchInfo")
162+
?.GetMethod("Capture", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(Exception) }, null);
163+
164+
ExceptionDispatchInfoThrowMethod = mscorlib
165+
?.GetType("System.Runtime.ExceptionServices.ExceptionDispatchInfo")
166+
?.GetMethod("Throw", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { }, null);
167+
}
152168
}
153169
}

tests/InterfaceInterception/InterfaceInterceptorFixture.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.ComponentModel;
77
using System.Linq;
88
using System.Reflection;
9+
using System.Runtime.CompilerServices;
910
using Microsoft.Practices.Unity.InterceptionExtension.Tests.MatchingRules;
1011
using Microsoft.Practices.Unity.InterceptionExtension.Tests.ObjectsUnderTest;
1112
using Microsoft.Practices.Unity.TestSupport;
@@ -1669,5 +1670,63 @@ public int CompareTo(Guid other)
16691670
return 0;
16701671
}
16711672
}
1673+
1674+
[TestMethod]
1675+
public void InterceptorCorrectlyRethrowsException()
1676+
{
1677+
IUnityContainer container = new UnityContainer()
1678+
.AddNewExtension<Interception>()
1679+
.RegisterType(typeof(IFoo), typeof(Foo))
1680+
.Configure<Interception>()
1681+
.SetInterceptorFor(typeof(IFoo), new InterfaceInterceptor())
1682+
.AddPolicy("AlwaysMatches")
1683+
.AddMatchingRule<AlwaysMatchingRule>()
1684+
.AddCallHandler<CallCountHandler>("callCount", new ContainerControlledLifetimeManager())
1685+
.Interception
1686+
.Container;
1687+
1688+
IFoo myFoo = container.Resolve<IFoo>();
1689+
1690+
try
1691+
{
1692+
myFoo.DoSomething();
1693+
Assert.Fail("Should have thrown");
1694+
}
1695+
catch (Exception ex)
1696+
{
1697+
CallCountHandler handler = (CallCountHandler)(container.Resolve<ICallHandler>("callCount"));
1698+
Assert.AreEqual(1, handler.CallCount);
1699+
Assert.IsInstanceOfType(ex, typeof(FooCrashedException));
1700+
1701+
var stackTrace = ex.StackTrace.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
1702+
Assert.IsTrue(stackTrace[0].Contains("DoSomethingLocal"), "stack trace is not full");
1703+
}
1704+
}
1705+
1706+
public interface IFoo
1707+
{
1708+
void DoSomething();
1709+
}
1710+
1711+
public class Foo : IFoo
1712+
{
1713+
public virtual void DoSomething()
1714+
{
1715+
DoSomethingLocal();
1716+
}
1717+
1718+
[MethodImpl(MethodImplOptions.NoInlining)]
1719+
protected void DoSomethingLocal()
1720+
{
1721+
throw new FooCrashedException("oops");
1722+
}
1723+
}
1724+
1725+
public class FooCrashedException : Exception
1726+
{
1727+
public FooCrashedException(string message) : base(message)
1728+
{
1729+
}
1730+
}
16721731
}
16731732
}

tests/VirtualMethodInterception/VirtualMethodInterceptorFixture.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Unity.Interception.Interceptors.TypeInterceptors.VirtualMethodInterception;
1313
using Unity.Interception.PolicyInjection;
1414
using Unity.Interception.PolicyInjection.Pipeline;
15+
using System.Runtime.CompilerServices;
1516

1617
namespace Microsoft.Practices.Unity.InterceptionExtension.Tests.VirtualMethodInterceptorTests
1718
{
@@ -866,6 +867,64 @@ public virtual X[] Test<X>() where X : IEnumerable<U>
866867
}
867868
}
868869
}
870+
871+
[TestMethod]
872+
public void InterceptorCorrectlyRethrowsException()
873+
{
874+
IUnityContainer container = new UnityContainer()
875+
.AddNewExtension<Interception>()
876+
.RegisterType(typeof(IFoo), typeof(Foo))
877+
.Configure<Interception>()
878+
.SetInterceptorFor(typeof(Foo), new VirtualMethodInterceptor())
879+
.AddPolicy("AlwaysMatches")
880+
.AddMatchingRule<AlwaysMatchingRule>()
881+
.AddCallHandler<CallCountHandler>("callCount", new ContainerControlledLifetimeManager())
882+
.Interception
883+
.Container;
884+
885+
IFoo myFoo = container.Resolve<IFoo>();
886+
887+
try
888+
{
889+
myFoo.DoSomething();
890+
Assert.Fail("Should have thrown");
891+
}
892+
catch (Exception ex)
893+
{
894+
CallCountHandler handler = (CallCountHandler)(container.Resolve<ICallHandler>("callCount"));
895+
Assert.AreEqual(1, handler.CallCount);
896+
Assert.IsInstanceOfType(ex, typeof(FooCrashedException));
897+
898+
var stackTrace = ex.StackTrace.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
899+
Assert.IsTrue(stackTrace[0].Contains("DoSomethingLocal"), "stack trace is not full");
900+
}
901+
}
902+
903+
public interface IFoo
904+
{
905+
void DoSomething();
906+
}
907+
908+
public class Foo : IFoo
909+
{
910+
public virtual void DoSomething()
911+
{
912+
DoSomethingLocal();
913+
}
914+
915+
[MethodImpl(MethodImplOptions.NoInlining)]
916+
protected void DoSomethingLocal()
917+
{
918+
throw new FooCrashedException("oops");
919+
}
920+
}
921+
922+
public class FooCrashedException : Exception
923+
{
924+
public FooCrashedException(string message) : base(message)
925+
{
926+
}
927+
}
869928
}
870929

871930
public partial class DerivedTypeCreator

0 commit comments

Comments
 (0)