Search code examples
c#postsharponexception

Different Aspects to handle different Exceptions


From the reading that I have done, I expected that I would be able to create different Aspects inherited from OnExceptionAspect that would allow me to handle different Exceptions differently in my code.

To this end I have created two Aspect classes as follows:

[Serializable]
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
public class CommonExceptionAspect : OnExceptionAspect
{
    public override void OnException(MethodExecutionArgs args)
    {
        string msg = string.Format("{0} had an error @ {1}: {2}\n{3}",
        args.Method.Name, DateTime.Now,
        args.Exception.Message, args.Exception.StackTrace);

        Trace.WriteLine(msg);

        if (args.Exception.GetType() != typeof (PppGeneralException))
        {
            throw new Exception("There was a problem");
        }
        else
        {
            args.FlowBehavior = FlowBehavior.RethrowException;
        }
    }
}

And the other aspect class:

[Serializable]
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
[MulticastAttributeUsage(MulticastTargets.Method, TargetMemberAttributes = (MulticastAttributes.Public | MulticastAttributes.NonAbstract | MulticastAttributes.Instance | MulticastAttributes.UserGenerated))] 
public class AuthenticationExceptionAspect : OnExceptionAspect
{
    public override void OnException(MethodExecutionArgs args)
    {
        string msg = string.Format("{0} had an error @ {1}: {2}\n{3}",
        args.Method.Name, DateTime.Now,
        args.Exception.Message, args.Exception.StackTrace);

        Trace.WriteLine(msg);

        throw new Exception("You are not authorized!");
    }

    public override Type GetExceptionType(System.Reflection.MethodBase targetMethod)
    {
        return typeof(AuthenticationException);
    }
}

My caller methods are as follows:

   public void EstablishConnection(string connectionString, DateTime d1, int connections)
    {
        Thread.Sleep(5000);
        if (connectionString.Length > 0)
        {
            throw new ExternalException("This is my external exception");
        }
    }

    public void StopDatabase(string connectionString)
    {
        Thread.Sleep(5000);

        if (connectionString.Length > 0)
        {
            throw new AuthenticationException("This is my detailed exception");
        }
        else
        {
            throw  new ArgumentException("This is just an argument exception");
        }
    }

I have the following entries in the AssemblyInfo.cs file:

[assembly: CommonExceptionAspect(AspectPriority = 3, AttributePriority = 1)]
[assembly: CommonExceptionAspect(AttributeExclude = true, AspectPriority = 3, AttributePriority = 0, AttributeTargetMembers = "ConsoleApplication3.ConnectionManager.StopDatabase", AttributeTargetTypeAttributes = MulticastAttributes.Public, AttributeTargetMemberAttributes = MulticastAttributes.Public, AttributeTargetElements = MulticastTargets.Method)]
[assembly: AuthenticationExceptionAspect(AspectPriority = 1)]

My expectation was that when the first caller method raise the "ExternalException" the OnException method of the "CommonExceptionAspect" would handle it. And when the "AuthenticationException" was raised from the second caller method, OnException method of the "AuthenticationExceptionAspect".

But in both scenarios the call goes to the "CommonExceptionAspect". Could someone please point me what I am doing wrong? If this understanding is incorrect and if this scenario is at all possible to achieve.

Thanks loads in advance.


Solution

  • In case of AspectPriority the higher number means that the aspect (or more precisely the transformation) would be applied first. Therefore in your case you are applying the CommonExceptionAspect first and this aspect would receive all exceptions regardless of the other aspect.

    You need to set the priorities other way around.

    As a sidenote - composition of multiple OnException (or OnMethodBoundary) aspects does not create single try-catch block with multiple catch statements, but will create multiple nested try-catch blocks. Thus, the behavior can be different.