Skip to content

Commit 20a0104

Browse files
authored
Merge pull request #6 from istagir/master
Merging fixes for Issue #3 (exception.StackTrace is truncated)
2 parents e5a2707 + 8dfb430 commit 20a0104

File tree

5 files changed

+160
-2
lines changed

5 files changed

+160
-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: 60 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;
@@ -21,6 +22,7 @@
2122
using Unity.Interception.PolicyInjection.Pipeline;
2223
using Unity.Interception.PolicyInjection.Policies;
2324
using Unity.Interception.Utilities;
25+
using Unity.Lifetime;
2426

2527
namespace Microsoft.Practices.Unity.InterceptionExtension.Tests.InterfaceInterception
2628
{
@@ -1669,5 +1671,63 @@ public int CompareTo(Guid other)
16691671
return 0;
16701672
}
16711673
}
1674+
1675+
[TestMethod]
1676+
public void InterceptorCorrectlyRethrowsException()
1677+
{
1678+
IUnityContainer container = new UnityContainer()
1679+
.AddNewExtension<Interception>()
1680+
.RegisterType(typeof(IFoo), typeof(Foo))
1681+
.Configure<Interception>()
1682+
.SetInterceptorFor(typeof(IFoo), new InterfaceInterceptor())
1683+
.AddPolicy("AlwaysMatches")
1684+
.AddMatchingRule<AlwaysMatchingRule>()
1685+
.AddCallHandler<CallCountHandler>("callCount", new ContainerControlledLifetimeManager())
1686+
.Interception
1687+
.Container;
1688+
1689+
IFoo myFoo = container.Resolve<IFoo>();
1690+
1691+
try
1692+
{
1693+
myFoo.DoSomething();
1694+
Assert.Fail("Should have thrown");
1695+
}
1696+
catch (Exception ex)
1697+
{
1698+
CallCountHandler handler = (CallCountHandler)(container.Resolve<ICallHandler>("callCount"));
1699+
Assert.AreEqual(1, handler.CallCount);
1700+
Assert.IsInstanceOfType(ex, typeof(FooCrashedException));
1701+
1702+
var stackTrace = ex.StackTrace.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
1703+
Assert.IsTrue(stackTrace[0].Contains("DoSomethingLocal"), "stack trace is not full");
1704+
}
1705+
}
1706+
1707+
public interface IFoo
1708+
{
1709+
void DoSomething();
1710+
}
1711+
1712+
public class Foo : IFoo
1713+
{
1714+
public virtual void DoSomething()
1715+
{
1716+
DoSomethingLocal();
1717+
}
1718+
1719+
[MethodImpl(MethodImplOptions.NoInlining)]
1720+
protected void DoSomethingLocal()
1721+
{
1722+
throw new FooCrashedException("oops");
1723+
}
1724+
}
1725+
1726+
public class FooCrashedException : Exception
1727+
{
1728+
public FooCrashedException(string message) : base(message)
1729+
{
1730+
}
1731+
}
16721732
}
16731733
}

tests/VirtualMethodInterception/VirtualMethodInterceptorFixture.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77
using System.Reflection;
88
using Microsoft.Practices.Unity.TestSupport;
99
using Microsoft.VisualStudio.TestTools.UnitTesting;
10+
using Unity;
1011
using Unity.Interception;
12+
using Unity.Interception.ContainerIntegration;
1113
using Unity.Interception.Interceptors;
1214
using Unity.Interception.Interceptors.TypeInterceptors.VirtualMethodInterception;
1315
using Unity.Interception.PolicyInjection;
1416
using Unity.Interception.PolicyInjection.Pipeline;
17+
using Unity.Lifetime;
18+
using System.Runtime.CompilerServices;
1519

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

871933
public partial class DerivedTypeCreator

0 commit comments

Comments
 (0)