I have developed an Outlook VSTO addin. Some tasks should be made on a background thread. Typically, checking something in my local db or invoking a web request. After reading several posts, I dropped the idea of calling the Outlook Object Model (OOM) in a background thread.
I have some wpf controls and I successfully managed to use the .NET 40 TPL to perform the async task and when completed to "finish" the job (i.e. accessing the UI or the OOM) in the Main VSTA Thread.
To do so I use a syntax of the form:
Task<SomeResult> task = Task.Factory.StartNew(()=>{
//Do long tasks that have nothing to do with UI or OOM
return SomeResult();
});
//now I need to access the OOM
task.ContinueWith((Task<SomeResult> tsk) =>{
//Do something clever using SomeResult that uses the OOM
},TaskScheduler.FromCurrentSynchronizationContext());
So far so good. But now I want to do something similar when hooking an event in the OOM where there are no Form/WPF control. Precisely, my problem comes from the fact that TaskScheduler.FromCurrentSynchronizationContext() throws an exception.
For instance,
Items inboxItems = ...;
inboxItems.ItemAdd += AddNewInboxItems;
private void AddNewInboxItems(object item)
{
Task<SomeResult> task = Task.Factory.StartNew(()=>{
//Do long tasks that have nothing to do with OOM
return SomeResult()});
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
/* Ouch TaskScheduler.FromCurrentSynchronizationContext() throws an InvalidOperationException, 'The current SynchronizationContext may not be used as a TaskScheduler.' */
task.ContinueWith((Task<SomeResult> tsk) =>{
//Do something clever using SomeResult that uses the OOM
}),scheduler};
}
/* Ouch TaskScheduler.FromCurrentSynchronizationContext() throws an InvalidOperationException, 'The current SynchronizationContext may not be used as a TaskScheduler.' */
Note that I tried to create a TaskScheduler in addin initialization and putting it in a singleton as suggested here. But it does not work, the continuation task is not performed in the desired VSTA Main thread but another one (inspected with VisualStudio).
Any idea ?
There is known bug that SynchronizationContext.Current might be null in several places where it should not (including office add-ins). That bug was fixed in .NET 4.5. But since you cannot upgrade to .NET 4.5, you have to find a workaround. As a suggestion, try to do:
System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
when initializing your addon.
You can use the SynchronizationContext class which provides the basic functionality for propagating a synchronization context in various synchronization models. The Post method dispatches an asynchronous message to a synchronization context, i.e. the Post method starts an asynchronous request to post a message. See Using SynchronizationContext for sending events back to the UI for WinForms or WPF for more information and sample code.
FYI The Current property allows to get the synchronization context for the current thread. This property is useful for propagating a synchronization context from one thread to another.
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