F#Async.FromBeginEnd没有捕获异常

时间:2012-01-04 04:37:55

标签: asynchronous f# azure-table-storage

我无法解决为什么以下代码无法捕获异常。这是我第一次使用F#中的Async,所以我确定它很简单

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

如果我运行它并且已经创建了表,则表示代码中没有处理类型为StorageClientException的异常,特别是指向FromBeginEnd调用的client.EndCreateTable部分

3 个答案:

答案 0 :(得分:4)

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

我认为你可以在这里抓住更新的FSharp.Core:http://www.microsoft.com/download/en/details.aspx?DisplayLang=en&id=15834

答案 1 :(得分:2)

如果异常的原因是该表已经存在,为什么不使用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([||])

奇怪的是代码在F#Interactive中正常工作,但在Visual Studio中调试为Windows应用程序时无法捕获异常(无论是调试还是发布配置)。即使是陌生人,如果在Visual Studio之外作为应用程序执行,它也能正常工作。

如果你想知道,这个程序改编自a MSDN example,它表现出相同的问题。

更新2:

http://cs.hubfs.net/topic/Some/0/59516已经提出了类似的问题。正如@ildjarn和@Brian所指出的,VS2010 SP1中修复了这个bug。如果没有VS2010 SP1,您可以使用F#Interactive测试代码并在VS外部执行应用程序而不会出现任何问题。

答案 2 :(得分:2)

感谢Don Syme, 解决方案是关闭调试“只是我的代码”。 调试 - &gt;选项和设置 - &gt;一般 - &gt;取消选中“仅启用我的代码(仅管理)

这仍然是Windows 8消费者预览版中出现的Visual Studio 11测试版的问题。