How can I prevent an entire application (process) crash when AccessViolationException (or another Corrupted State Exception) is thrown in an AppDomain in .NET 4.6? My goal is to wrap a 3rd party library (GdPicture.NET barcode reader) in its AppDomain, which intermittently crashes IIS worker process according to IIS crash dumps. In other words, I'd like to isolate 3rd party library call in its own app domain so that it can fail within itself without taking the entire web site down.
In the sample code below, if I don't use HandleProcessCorruptedStateExceptions attribute I cannot catch the AccessViolationException (wrapped in TargetInvocationException) which is thrown in a different AppDomain (in ClassLibrary1.dll). If I decorate HandleProcessCorruptedStateExceptions (for only the 2nd AppDomain call), is it safe for the main process to continue or does it become to an unstable state?
Visual Studio solution with two projects (a console app and a class library).
using System;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Security;
namespace StackOverflowQuestion
{
class Program
{
static void Main(string[] args)
{
new Tester().RunTest();
}
}
class Tester
{
public void RunTest()
{
var myTestAppDomain = AppDomain.CreateDomain("My Test AppDomain");
var loader = (Loader)myTestAppDomain.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
TestHandleProcessCorruptedStateExceptions(loader, myTestAppDomain);
// how can I make sure process doesn't crash when AppDomain "My Test AppDomain" crashes
Console.WriteLine("This won't be written to console unless [HandleProcessCorruptedStateExceptions] attribute is present...");
// keep console window open
Console.ReadKey();
}
// [HandleProcessCorruptedStateExceptions, SecurityCritical]
private void TestHandleProcessCorruptedStateExceptions(Loader loader, AppDomain appDomain)
{
Console.WriteLine("Loading 3rd party lib ClassLibrary1.dll...");
loader.LoadAssembly(@"..\..\..\ClassLibrary1\bin\debug\ClassLibrary1.dll");
try
{
// executing static method in dummy 3rd party dll in a different app domain (named "My Test AppDomain")
loader.ExecuteStaticMethod("ClassLibrary1.Class1", "DoStuff", DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString());
}
catch (TargetInvocationException)
{
AppDomain.Unload(appDomain);
Console.WriteLine("DoStuff failed. This won't be written to console unless [HandleProcessCorruptedStateExceptions] attribute is present...");
}
}
}
class Loader : MarshalByRefObject
{
private Assembly _assembly;
public void LoadAssembly(string path)
{
_assembly = Assembly.Load(AssemblyName.GetAssemblyName(path));
}
public object ExecuteStaticMethod(string typeName, string methodName, params object[] parameters)
{
var type = _assembly.GetType(typeName);
// assume there is no overloads for simplicity
var method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public);
return method.Invoke(null, parameters);
}
}
}
And this is the code in Class1.cs in ClassLibrary1 project:
using System;
using System.Runtime.InteropServices;
namespace ClassLibrary1
{
public class Class1
{
public static void DoStuff(string msg)
{
Console.WriteLine("Throwing AccessViolationException now...");
// throw an AccessViolationException which cannot be caught in a try/catch block
FakeAccessViolationException();
Console.WriteLine("Class1.DoStuff: " + msg);
}
private static void FakeAccessViolationException()
{
var ptr = new IntPtr(42);
Marshal.StructureToPtr(42, ptr, true);
}
}
}