开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜