Is it possible to attach to the AppDomain.UnhandledException event?
I'm trying to create an AppDomain and attach to its UnhandledException event from F#, and I'm not having much luck. In my event handler I need a reference to the domain that fired the event, as well as the event arguments.
To reproduce this issue, the following code must be run in a compiled application. Running it in F# Interactive produces a different, probably-not-related error.
open System
open System.Reflection
let domainError (domain:AppDomain) (args:UnhandledExceptionEventArgs) =
()
let domain = AppDomain.CreateDomain("test")
domain.UnhandledException
|> Event.add (domainError domain)
This compiles just fine, but at runtime I get the following error:
SerializationException: Type 'Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers+h@720' in assembly 'FSharp.Core, Version=4.0.0.0, Cu开发者_JS百科lture=neutral, PublicKeyToken=b03f5f7f11d50a3a' is not marked as serializable.
The stack trace that goes along with this error is as follows:
at System.AppDomain.add_UnhandledException(UnhandledExceptionEventHandler value)
at Program.clo@9.Invoke(UnhandledExceptionEventHandler eventDelegate) in c:\users\joel\documents\visual studio 2010\Projects\EventTest\Program.fs:line 9
at Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers.CreateEvent@716.Subscribe(IObserver`1 observer)
at Microsoft.FSharp.Control.CommonExtensions.SubscribeToObservable[T](IObservable`1 x, FSharpFunc`2 callback)
at Microsoft.FSharp.Control.EventModule.Add[T,TDel](FSharpFunc`2 callback, IEvent`2 sourceEvent)
at <StartupCode$EventTest>.$Program.main@() in c:\users\joel\documents\visual studio 2010\Projects\EventTest\Program.fs:line 9
Now I obviously can't make Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers+h@720
serializable, so can anyone suggest a workable way of attaching to this particular event? Thanks for any suggestions.
Update
Thanks to a suggestion from ChaosPandion, this version works:
open System
open System.Reflection
let domainError (sender:obj) (args:UnhandledExceptionEventArgs) =
let problemDomain = sender :?> AppDomain
printfn "Unhandled exception in app domain: %s" problemDomain.FriendlyName
()
let domain = AppDomain.CreateDomain("test")
domain.UnhandledException.AddHandler(UnhandledExceptionEventHandler(domainError))
After a bit more tweaking I found this example will fail:
let domainError (domain:AppDomain) =
let handler (sender:obj) (e:UnhandledExceptionEventArgs) =
let msg = (e.ExceptionObject :?> Exception).Message
printfn "An exception was unhandled in %s\nMessage:%s" domain.FriendlyName msg
new UnhandledExceptionEventHandler(handler)
let main() =
let domain = AppDomain.CreateDomain("test")
let handler = domainError domain
domain.UnhandledException.AddHandler handler
I broke open Reflector and found the root cause. (Which is actually quite obvious now that I think about it.)
internal class handler@28 : OptimizedClosures.FSharpFunc<object, UnhandledExceptionEventArgs, Unit>
{
// Fields
public AppDomain domain;
// Methods
internal handler@28(AppDomain domain);
public override Unit Invoke(object sender, UnhandledExceptionEventArgs e);
}
This pretty much means that the only way you can get this to work is to not create the closure around the domain object. I am not sure if this will work for you but you may want to try using the following from within the handler.
AppDomain.CurrentDomain
精彩评论