Asynchronous F#Async.FromBegined未捕获异常

Asynchronous F#Async.FromBegined未捕获异常,asynchronous,f#,azure-table-storage,Asynchronous,F#,Azure Table Storage,我很难理解为什么下面的代码没有捕获异常。这是我第一次在F#中使用异步,所以我确信它很简单 open System open Microsoft.WindowsAzure open Microsoft.WindowsAzure.StorageClient open System.Windows.Forms let mutable connection = "UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://ipv4.fidd

我很难理解为什么下面的代码没有捕获异常。这是我第一次在F#中使用异步,所以我确信它很简单

open System
open Microsoft.WindowsAzure
open Microsoft.WindowsAzure.StorageClient
open System.Windows.Forms

let mutable connection = "UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://ipv4.fiddler"

CloudStorageAccount.SetConfigurationSettingPublisher(fun cName cPublisher ->
                                                      cPublisher.Invoke connection |> ignore)

let storageAccount = CloudStorageAccount.Parse connection

let createTable tableName =
        let client = storageAccount.CreateCloudTableClient()
        async{
            try
                do! Async.FromBeginEnd(tableName, client.BeginCreateTable , client.EndCreateTable)
                MessageBox.Show "Created" |>ignore
            with 
            | :? StorageClientException -> printfn "failed"; MessageBox.Show("failed to create table") |> ignore
            | _ -> printfn "Failed with unknown exception"
        } |> Async.Start

[<EntryPoint; STAThread>]
let main(args) =
    let form = new Form()
    let btn = new Button(Text = "Click")
    btn.Click.AddHandler(fun _ _ -> createTable "SomeNewTable")
    form.Controls.Add btn
    let result = form.ShowDialog()
    0
开放系统
打开Microsoft.WindowsAzure
打开Microsoft.WindowsAzure.StorageClient
打开System.Windows.Forms
让mutable connection=“UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://ipv4.fiddler"
CloudStorageAccount.SetConfigurationSettingPublisher(趣味cName CPPublisher->
cPublisher.Invoke连接|>忽略)
让storageAccount=CloudStorageAccount.Parse连接
让createTable表名=
让client=storageAccount.CreateCloudTableClient()
异步的{
尝试
do!Async.FromBeginEnd(表名,client.BeginCreateTable,client.EndCreateTable)
MessageBox.Show“Created”|>忽略
具有
|:?StorageClientException->printfn“失败”;MessageBox.Show(“未能创建表”)|>忽略
|->printfn“因未知异常而失败”
}|>异步启动
[]
let main(args)=
let form=新表单()
让btn=新建按钮(Text=“单击”)
btn.Click.AddHandler(乐趣->createTable“SomeNewTable”)
form.Controls.Add btn
让结果=form.ShowDialog()
0
如果我运行此操作并且表已经创建,则表示代码中没有处理StorageClientException类型的异常,特别是指向FromBeginEnd调用的client.EndCreateTable部分,如果异常的原因是表已经存在,为什么不改用
BeginCreateTableIfNotExist
/
EndCreateTableIfNotExist

更新:

该漏洞与Windows Azure无关。我能够用一个简单的程序重现相同的行为:

open System
open System.Windows.Forms

let bufferData = Array.zeroCreate<byte> 100000000

let async1 filename =        
    async{
        try 
            use outputFile = System.IO.File.Create(filename)
            do! outputFile.AsyncWrite(bufferData)   
            MessageBox.Show("OK") |> ignore         
        with 
        | :? ArgumentException -> printfn "Failed with ArgumentException"; MessageBox.Show("Failed with ArgumentException") |> ignore         
        | _ -> printfn "Failed with unknown exception"; MessageBox.Show("Failed with unknown exception") |> ignore         
    } |> Async.Start

let main(args) =
    let form = new Form(Text = "Test Form")
    let button1 = new Button(Text = "Start")
    let button2 = new Button(Text = "Start Invalid", Top = button1.Height + 10)        
    form.Controls.AddRange [| button1; button2; |]
    button1.Click.Add(fun args -> async1 "longoutput.dat")
    // Try an invalid filename to test the error case.
    button2.Click.Add(fun args -> async1 "|invalid.dat")    
    let result = form.ShowDialog()
    0

let _ = main([||])
开放系统
打开System.Windows.Forms
让bufferData=Array.zeroCreate 100000000
让async1文件名=
异步的{
尝试
使用outputFile=System.IO.File.Create(文件名)
do!outputFile.AsyncWrite(缓冲数据)
MessageBox.Show(“OK”)|>忽略
具有
|:?ArgumentException->printfn“因ArgumentException而失败”MessageBox.Show(“因ArgumentException而失败”)|>忽略
|->printfn“因未知异常而失败”MessageBox.Show(“因未知异常而失败”)|>忽略
}|>异步启动
let main(args)=
let form=新表单(Text=“测试表单”)
let button1=新按钮(Text=“开始”)
let button2=新按钮(Text=“开始无效”,Top=按钮1.高度+10)
form.Controls.AddRange[|按钮1;按钮2;|]
按钮1.单击.添加(趣味参数->异步1“longoutput.dat”)
//请尝试使用无效的文件名来测试错误情况。
按钮2。单击。添加(趣味参数->异步1“|无效的.dat”)
让结果=form.ShowDialog()
0
让ux=main([| |])
奇怪的是,代码在F#Interactive中运行良好,但在VisualStudio中作为Windows应用程序进行调试时(无论是调试还是发布配置)无法捕获异常。更奇怪的是,如果在VisualStudio之外作为应用程序执行,它仍然可以正常工作

如果你想知道,这个节目是根据同样的问题改编的

更新2:


一个类似的问题也被问到了。正如@ildjarn和@Brian指出的,这个bug已经在VS2010 SP1中修复。如果没有VS2010 SP1,您也可以使用F#Interactive测试代码,并在VS外部执行应用程序,而不会出现任何问题。

这听起来像是VS2010 SP1中FSharp.Core中修复的问题。.NET
SynchronizationContext
s改变了它们的行为(我认为是在.NET 4.0 SP1中),我们需要在F#运行时中进行相应的更改,以便异步正确处理线程关联

我想你可以在这里找到更新的FSharp.Core:

多亏了唐·赛姆, 解决方案是关闭调试“仅我的代码”。 调试->选项和设置->常规->取消选中“仅启用我的代码(仅限托管)”


Windows 8消费者预览版附带的Visual Studio 11 beta版仍然存在问题。

有点小问题,但是如果调用了异常处理程序,则可能不会从UI线程调用它,因此
MessageBox.Show
在何处不是一个好主意。如果替换
a,会有什么不同吗sync.Start
Async.RunSynchronously
同步?是的,消息框目前只是用于测试。稍后它将被替换为回调函数。替换为RunSynchronously不会改变任何内容:(您的目标是.NET的哪个版本?您是否安装了VS2010 SP1?对于本例来说,这很好,但是对于从FromBeginEnd构造创建的其他操作,它也会使对表服务的请求数量翻倍,对于高容量站点,这可能是一件非常糟糕的事情。为什么?”如果表不存在,则创建该表“将请求数增加一倍”,如果表已存在,则创建该表并引发异常"?
CreateTableIfNotExist
仍然可以抛出
StorageClientException
;这不是一个答案。@JoelMueller我很确定,如果你通过fiddler运行请求,你会看到一个get请求,后面跟着一个create。但不管怎样,ildjarn有权抛出它。这是一个混合应用程序,所以我不能指望总是能够到达table SERVICE当作为编译应用程序运行时,您的编辑行为对我来说是正确的——例如,我得到一个消息框,读作“Failed with ArgumentException”。您的目标是.NET的哪个版本?您是否安装了VS2010 SP1?嗯,很遗憾,没有。我已经安装了SP1,在跟踪链接时可以进行修复,我在Visual Studio 11预览中看到了相同的beahviour:(我无法使用@pad的