Having
public class ObjFromOtherAppDomain : MarshalByRefObject
{
public async void Do(MarshalableCompletionSource<bool> source)
{
await Task.Delay(1000);
source.SetResult(true);
}
}
public class MarshalableCompletionSource<T> : MarshalByRefObject
{
private readonly TaskCompletionSource<T> tsc = new TaskCompletionSource<T>();
public void SetResult(T result) => tsc.SetResult(result);
public void SetException(Exception[] exception) => tsc.SetException(exception);
public void SetCanceled() => tsc.SetCanceled();
public Task<T> Task => tsc.Task;
}
Doing
- Create new
AppDomain - Create an instance of
ObjFromOtherAppDomainwithin the newAppDomain - invoke
Domethod passingMarshalableCompletionSourcein order later to know whenasyncDomethod is completed. - Once
Domethod is completed, trying toUnloadtheAppDomain
public static async Task Main()
{
var otherDomain = AppDomain.CreateDomain("other domain");
var objFromOtherAppDomain = (ObjFromOtherAppDomain)otherDomain
.CreateInstanceAndUnwrap(
typeof(ObjFromOtherAppDomain).Assembly.FullName,
typeof(ObjFromOtherAppDomain).FullName);
var source = new MarshalableCompletionSource<bool>();
objFromOtherAppDomain.Do(source);
await source.Task;
//await Task.Yield();
AppDomain.Unload(otherDomain);
}
Getting
System.Threading.ThreadAbortException: 'Thread has aborted. (Exception from HRESULT: 0x80131530) exception
Fix
Uncomment await Task.Yield(); line and Unload works well.
Short analysis
Main thread enters Do method and on the line await Task.Delay(1000), Main thread returns back to Main method, while new background thread gets pulled from ThreadPool (it's happening in otherDomain) and continues execution of continuation, in this case, rest of the Do method.
After that, the same (background) thread starts executing rest of the Main method (the part after await source.Task)
At that moment background thread hits AppDomain.Unload(otherDomain), it should be done in otherDomain and happily unload it, but, apparently, it's not.
If i'll yield (release, set free) that background thread by await Task.Yield(), new Background thread comes into play and does AppDomain.Unload happily.
Why is that?