locked
Async Postcondition wraps the task exception within the additional AggregateException (Version 1.6.60505.10) RRS feed

  • Question

  • Problem

    Suppose we have the following async method:

    async Task<int> ParseAsync(string value)
    {
        await Task.Delay(3000); // simulate some "expensive" call
    
        throw new FormatException();
    }

    So calling the method works as usual:

    try
    {
        var x = await ParseAsync("123");
        ...
    }
    catch (FormatException)
    {
        // some exception handling
    }

    However, just adding the new async ensure breaks the code:

    async Task<int> ParseAsync(string value)
    {
        Contract.Ensures(Contract.Result<int>() > 0); // async ensure
    
        await Task.Delay(3000); // simulate some "expensive" call
    
        throw new FormatException();
    }


    To catch the exception I'm now forced to handle two cases:

    try
    {
        var x = await ParseAsync("123");
        ...
    }
    catch (FormatException)
    {
        // exception handling
    }
    catch (AggregateException e)
    {
        if (e.InnerException is FormatException)
        {
            // same exception handling as above
        }
    }

    The reason is that the generated CheckPost uses the Result property of the passed Task. The Result property throws the FormatException that is wrapped within the AggregateException. This makes the CheckPost method to throw the caught AggregateException wrapping with its own AggregateException.

    The catch block (after awaiting) in the calling method unwraps the AggregateException to catch the inner exception, but the inner exception is another AggregateException…


    Suggested Solution

    The imaginable implementation of the generated CheckPost method could be:

    public T CheckPost(Task<T> task)
    {
        Task<T> t = task;
        T result;
        try
        {
            t = t.Result;
        }
        catch (AggregateException e)
        {
            if (e.InnerExceptions.Count == 1)
            {
                throw e.InnerException; // this will lose the wrapping AggregateException
            }
            throw; // just rethrow the original exception if there are more than 1 exception
        }
        ...
    }

    Is the behavior buggy or intentional?






    Tuesday, June 24, 2014 8:54 AM

All replies

  • Still occurs with CC 1.7.11106.10.

    It would consider this a bug as the postcondition needs not to be checked in case the guarded method throws an exception.

    Thursday, December 4, 2014 1:52 PM
  • If anyone runs across this in the future like me then go here: https://github.com/Microsoft/CodeContracts/commit/9b96aa83234cc7e0dd2b636341904eb1f15b8782

    The bug has been fixed and merged, but at the time of this post it has not yet been released.

    Related issue: https://github.com/Microsoft/CodeContracts/issues/155
    • Edited by Micah Zoltu Sunday, September 6, 2015 9:38 PM
    Sunday, September 6, 2015 9:37 PM