Our application has a lot of calls to Task.Factory.StartNew(Action action). Unfortunately, when doing this, the culture is not set, and furthermore, there is no error handling. I began with a starter class that would do both:
public static class TaskBuilder
{
private static Action<System.Exception> _exceptionCallback;
public static Task StartNew(Action action, CultureInfo cultureInfo, Action<System.Exception> exceptionCallback)
{
_exceptionCallback = exceptionCallback;
return Task.Factory.StartNew(() =>
{
Thread.CurrentThread.CurrentUICulture = cultureInfo;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name);
action.Invoke();
}).ContinueWith(t => ManageException(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
}
private static void ManageException(System.Exception e)
{
if (_exceptionCallback != null)
{
_exceptionCallback(e);
}
}
}
But then I realized that a better approach would be an interceptor. I would like to intercept the call to StartNew so that the new thread contains the culture and error handling code. My attempt at this produced the following code:
public class TaskInterceptionHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Thread.CurrentThread.CurrentUICulture = // How do I get parent cultureInfo?;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name);
var methodReturn = getNext().Invoke(input, getNext);
if (methodReturn.Exception != null)
{
// How do I throw the exception to the calling thread here?
}
return methodReturn;
}
public int Order { get; set; }
}
Here is where I'm stumped. Firstly, how do I get the parent CultureInfo? Secondly How do I return the exception to the calling thread? and How do I use this class in my calls? I.e. how do I replace the existing Task.Factory.StartNew(..)
I'm using Unity, and I'm in unfamiliar territory here. Any help or guidance would be appreciated, or is there even a better solution? Maybe I'm starting on the wrong foot?
I'm using .NET 4.5
Most of the feedback I'm getting below seems to avoid the interceptor route. Is it safe to assume using an interceptor is the wrong way to go? If someone can guide me in that direction, it would allow me to do a comparison. If the answer to the question is yes, I'd like to know how?
StartNew(Action<Object>, Object, CancellationToken, TaskCreationOptions, TaskScheduler) Creates and starts a task for the specified action delegate, state, cancellation token, creation options and task scheduler.
Run(action) internally uses the default TaskScheduler , which means it always offloads a task to the thread pool. StartNew(action) , on the other hand, uses the scheduler of the current thread which may not use thread pool at all!
Rather than setting the culture in every task, I suggest you set the CultureInfo.DefaultThreadCurrentCulture
and CultureInfo.DefaultThreadCurrentUICulture
properties to set the culture globally for all future threads.
Regarding error handling, it's probably easier to use await
in a try/catch block, rather than passing a delegate to handle the exception:
try
{
// Task.Run is similar to Task.Factory.StartNew, but easier to use
await Task.Run(...);
}
catch(Exception ex)
{
// handle it...
}
BTW, your current error handling mechanism won't work if you have more than one task running at the same time, since there's only one _exceptionCallback
for all tasks...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With