Created
July 2, 2015 21:39
-
-
Save govert/fd4cf051deada526039f to your computer and use it in GitHub Desktop.
A sample about recovering caller information for async calls, and the effect of different async keys
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Text; | |
using System.Threading; | |
using ExcelDna.Integration; | |
using ExcelDna.Logging; | |
namespace AsyncCaller | |
{ | |
public class AddIn : IExcelAddIn | |
{ | |
public void AutoOpen() | |
{ | |
ExcelIntegration.RegisterUnhandledExceptionHandler(ErrorHandler); | |
} | |
public void AutoClose() | |
{ | |
} | |
object ErrorHandler(object exception) | |
{ | |
object caller; | |
Exception innerException; | |
ExcelAsyncException asyncEx = exception as ExcelAsyncException; | |
if (asyncEx != null) | |
{ | |
// Caller is already wrapped in async exception | |
caller = asyncEx.CallerReference; | |
innerException = asyncEx.InnerException; | |
} | |
else | |
{ | |
// Get caller for regular function | |
caller = XlCall.Excel(XlCall.xlfCaller); | |
innerException = (Exception)exception; | |
} | |
LogDisplay.WriteLine(caller.ToString() + " : " + innerException.Message); | |
return ExcelError.ExcelErrorValue; | |
} | |
} | |
public static class Functions | |
{ | |
public static object SlowAdd(double val1, double val2) | |
{ | |
Thread.Sleep(3000); | |
if (val1 == 0) | |
throw new ArgumentOutOfRangeException("val1"); | |
return val1 + val2; | |
} | |
public static object SlowAddAsync(double val1, double val2) | |
{ | |
string funcName = "SlowAddAsync"; | |
object asyncKey = new object[] { val1, val2 }; | |
return ExcelAsyncUtil.Run(funcName, asyncKey, () => SlowAdd(val1, val2)); | |
} | |
public static object SlowAddAsyncEx(double val1, double val2) | |
{ | |
// The asyncKey (together with the funcName string) will determine the RTD topic key, | |
// and thus which async calls are considered 'the same' | |
// If the caller is part of the key, then every async call (even those with exactly the same parameters) | |
// will be calculated separately, and can thus report separate errors. | |
// If the caller is not part of the asyncKey, the inner function will only be called once for | |
// a given set of parameter values, and hence only one of the calling references will be available | |
// in the error handler. | |
object caller = XlCall.Excel(XlCall.xlfCaller); | |
string funcName = "SlowAddAsyncEx"; | |
object asyncKey = new object[] { val1, val2, caller }; | |
// object asyncKey = new object[] { val1, val2 }; | |
return ExcelAsyncUtil.Run(funcName, asyncKey, () => | |
{ | |
try | |
{ | |
return SlowAdd(val1, val2); | |
} | |
catch (Exception ex) | |
{ | |
throw new ExcelAsyncException("Wrapped error", ex, caller); | |
} | |
}); | |
} | |
} | |
public class ExcelAsyncException : Exception | |
{ | |
public object CallerReference { get; private set; } | |
public ExcelAsyncException(string message, Exception innerException, object callerReference) | |
: base(message, innerException) | |
{ | |
CallerReference = callerReference; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment