2

I have a WPF-MVVM-application. I want to use async and await to make my UI responsive while loading and processing a file. I am getting an exception 'The calling thread cannot access this object because a different thread owns it' when a method which is awaited uses logging with log4net.

// The method returns 'void' because it is used by a DelegateCommand!
private async void LoadAndProcessFileAsync()
{
   this.MyBindingList.Clear(); // Works fine
   var importer = await Task.Run(() => new Importer());
   this.MyBindingList.Clear(); // Exception
}

All the importer does is:

public class Importer
{
  private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

  public Importer()
  {
    log.Info("Test");
  }
}

If I comment out the log.Info... and the static ILog-variable, everything works fine. The problem also occurs if I do the following:

private async void LoadAndProcessFileAsync()
{
   this.MyBindingList.Clear(); // Works fine
   var test = await Task.Run(() => Math.Sqrt(9));
   var importer = new Importer();
   this.MyBindingList.Clear(); // Exception
}

It disappears if I don't use await at all in the async method.

Why does this happen? How can I use await AND logging together? (I am using a third-party-library who uses log4net, so I can't change that code...).

Timitry
  • 2,646
  • 20
  • 26
  • 3
    Pretty sure the problem won't occur if you make the log non-static. A static log means that you're using the same object across multiple threads; hence why threads other than the main thread (which is the one that created all the static objects during initialization) have issues with accessing it. – Flater Nov 30 '17 at 09:09
  • 2
    How do you know what `Importer` does if it's third party library you don't own? – Evk Nov 30 '17 at 09:10
  • @Evk: I wrote `Importer` to reproduce the error. The third-party-library is xBim (open source), I'd have to check how exactly they handle their logging. – Timitry Nov 30 '17 at 09:14
  • 3
    So to clarify, this is exact code which reproduces a problem, not some pseudo code? – Evk Nov 30 '17 at 09:14
  • I did strip down that function and the other class to only these parts, yes, but did not (yet) bother to make a minimal (not-)working example. – Timitry Nov 30 '17 at 09:17
  • Are you sure your `DelegateCommand` executes the `async` method correctly? (That means, using `await` or `Task.Wait` etc) – dymanoid Nov 30 '17 at 09:18
  • 3
    Well then worth posting exact code which can reproduce this behavior, without stripping down anything (well, anything that is related for reproduction that is), because with current code it is not reproducable. – Evk Nov 30 '17 at 09:20
  • @dymanoid I am using `Prism.Mvvm`'s `DelegateCommand`, so I guess I can't mess up too much. While using the long-running original code, the UI was visible and did not hang. Then the `await` finished and the exception occured... – Timitry Nov 30 '17 at 09:22
  • Its not reproducible. – tabby Nov 30 '17 at 09:53

1 Answers1

2

Your async method examples both return void so will not be awaited, in order for a task to be awaited it must at least return Task, and if your having 'The calling thread cannot access this object because a different thread owns it" problems try using the dispatcher:

Application.Current.Dispatcher.Invoke(() => {Your Action;} );

async methods by their very nature run on a new thread

stuicidle
  • 297
  • 1
  • 8
  • It's not true that the `async void`-method is not being awaited, this works just fine. I tried your suggestion, however, `Application.Current` is `null`! That might have to do with my setup, I am calling C# from Fortran via a C++/CLI-Wrapper... I'll have to try if the error occurs with a simple C# application. – Timitry Nov 30 '17 at 12:37
  • 2
    It's also not true that `async methods by their very nature run on a new thread`. The task scheduler may run an `async` method on the calling thread synchronously if it's appropriate. Further more, there are some IO-bound tasks that don't need any thread at all. – dymanoid Nov 30 '17 at 14:51