{"id":641,"date":"2013-12-25T13:00:27","date_gmt":"2013-12-25T13:00:27","guid":{"rendered":"http:\/\/writeasync.net\/?p=641"},"modified":"2013-12-16T21:47:23","modified_gmt":"2013-12-16T21:47:23","slug":"alternatives-to-disposeasync","status":"publish","type":"post","link":"http:\/\/writeasync.net\/?p=641","title":{"rendered":"Alternatives to DisposeAsync"},"content":{"rendered":"<p>It stands to reason that <code>DisposeAsync<\/code> would be the asynchronous counterpart of <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.idisposable.dispose(v=vs.110).aspx\"><code>IDisposable.Dispose<\/code><\/a>. However, I recommend that you <strong>do not use the Dispose pattern for asynchronous cleanup<\/strong>. Why not?<\/p>\n<p>First off, an async version of Dispose would not work properly with the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/yh598w02.aspx\"><code>using<\/code> statement<\/a>. At best, you would have to roll your own with a <code>try<\/code>\/<code>finally<\/code> &#8212; except that you can&#8217;t <code>await<\/code> inside a <code>finally<\/code>. This means you&#8217;d need to block (e.g. by calling <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.threading.tasks.task.wait(v=vs.110).aspx\"><code>Task.Wait()<\/code><\/a>) which is obviously not a good async coding practice.<\/p>\n<p>Stepping back for a bit, if you think you need an asynchronous Dispose, you are already saying, &#8220;My class needs to do some I\/O-bound work to close itself down.&#8221; Two consequences of this are that the work could take significant time (e.g. flushing to a network file) and that the operations involved could fail (e.g. network connection is broken). These are antithetical to Dispose, which should be a <strong>fast<\/strong>, <strong>no-fail<\/strong> operation.<\/p>\n<p>It turns out that <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms731082(v=vs.110).aspx\">Windows Communication Foundation<\/a> (WCF) had this same problem years ago. This is why <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.servicemodel.icommunicationobject(v=vs.110).aspx\"><code>ICommunicationObject<\/code><\/a> has <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.servicemodel.icommunicationobject.abort(v=vs.110).aspx\"><code>Abort<\/code><\/a> (for <em>immediate<\/em> shutdown) and (Begin\/End)<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms195516(v=vs.110).aspx\"><code>Close<\/code><\/a> (for <em>orderly<\/em> shutdown).<\/p>\n<p>Now let&#8217;s craft a solution to the async Dispose problem in the spirit of the above guidance. First, we define a new interface which enhances IDisposable:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic interface IDestroyable : IDisposable\r\n{\r\n    Task DestroyAsync();\r\n}\r\n<\/pre>\n<p>Now we need an alternative to <code>using<\/code> which will always attempt to call <code>DestroyAsync<\/code> and guarantees that the object will be disposed at the end. This is a standard deferred exception pattern, as follows:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic static class AsyncEx\r\n{\r\n    public static async Task UsingAsync&lt;TDestroyable&gt;(\r\n        Func&lt;TDestroyable&gt; create,\r\n        Func&lt;TDestroyable, Task&gt; doAsync)\r\n        where TDestroyable : IDestroyable\r\n    {\r\n        \/\/ 'using' guarantees Dispose as long as create() succeeds\r\n        using (TDestroyable d = create())\r\n        {\r\n            List&lt;Exception&gt; exceptions = new List&lt;Exception&gt;();\r\n            try\r\n            {\r\n                await doAsync(d);\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                \/\/ catch and continue, we'll rethrow at the end\r\n                exceptions.Add(e);\r\n            }\r\n\r\n            try\r\n            {\r\n                await d.DestroyAsync();\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                \/\/ catch and continue, we'll rethrow at the end\r\n                exceptions.Add(e);\r\n            }\r\n\r\n            if (exceptions.Count &gt; 0)\r\n            {\r\n                \/\/ In case the above exceptions were already wrapped in\r\n                \/\/ AggregateException we should flatten everything here\r\n                \/\/ before rethrowing.\r\n                throw new AggregateException(exceptions).Flatten();\r\n            }\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Now for a trivial implementation of <code>IDestroyable<\/code> which allows to test all the success and failure paths using bit flags to identify which step, if any, we want to fail:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic sealed class MyObj : IDestroyable\r\n{\r\n    private readonly Stopwatch stopwatch;\r\n    private readonly string name;\r\n    private readonly int failureFlags;\r\n\r\n    public MyObj(string name, int failureFlags)\r\n    {\r\n        this.stopwatch = Stopwatch.StartNew();\r\n        this.name = name;\r\n        this.failureFlags = failureFlags;\r\n        this.FailIfStepMatches(1);\r\n    }\r\n\r\n    public async Task DoAsync()\r\n    {\r\n        await Task.Delay(1000);\r\n        this.Log(&quot;Done!&quot;);\r\n        this.FailIfStepMatches(2);\r\n    }\r\n\r\n    public async Task DestroyAsync()\r\n    {\r\n        await Task.Delay(1000);\r\n        this.Log(&quot;Destroyed!&quot;);\r\n        this.FailIfStepMatches(4);\r\n    }\r\n\r\n    public void Dispose()\r\n    {\r\n        this.Log(&quot;Disposed!&quot;);\r\n    }\r\n\r\n    private void Log(string message)\r\n    {\r\n        Console.WriteLine(\r\n            &quot;&#x5B;{0:00.000}] ({1}) {2}&quot;,\r\n            this.stopwatch.Elapsed.TotalSeconds,\r\n            this.name,\r\n            message);\r\n    }\r\n\r\n    private void FailIfStepMatches(int stepFlag)\r\n    {\r\n        if ((this.failureFlags &amp; stepFlag) != 0)\r\n        {\r\n            string message = &quot;Failing (flag &quot; + stepFlag + &quot;)!&quot;;\r\n            this.Log(message);\r\n            throw new InvalidOperationException(message);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>And finally, some sample code showing a few use cases &#8212; first, for success:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate static async Task SampleAsync()\r\n{\r\n    \/\/ One object, success\r\n    await AsyncEx.UsingAsync(\r\n        () =&gt; new MyObj(&quot;A&quot;, 0),\r\n        d =&gt; d.DoAsync());\r\n\r\n    Console.WriteLine(&quot;----&quot;);\r\n\r\n    Func&lt;MyObj, MyObj, Task&gt; doBothAsync = async delegate(MyObj a, MyObj b)\r\n    {\r\n        await a.DoAsync();\r\n        await b.DoAsync();\r\n    };\r\n\r\n    \/\/ Nested objects, success\r\n    await AsyncEx.UsingAsync(\r\n        () =&gt; new MyObj(&quot;A&quot;, 0),\r\n        d1 =&gt; AsyncEx.UsingAsync(\r\n            () =&gt; new MyObj(&quot;B&quot;, 0),\r\n            d2 =&gt; doBothAsync(d1, d2)));\r\n}\r\n<\/pre>\n<p>The &#8220;stacked using&#8221; case for nested objects shown above is obviously a bit more cumbersome than a standard using statement, but it&#8217;s not too bad if you keep the lambdas relatively short. The output from this code is as you would expect &#8212; last in, first out:<\/p>\n<p><code>[01.007] (A) Done!<br \/>\n[02.027] (A) Destroyed!<br \/>\n[02.027] (A) Disposed!<br \/>\n----<br \/>\n[01.009] (A) Done!<br \/>\n[02.018] (B) Done!<br \/>\n[03.038] (B) Destroyed!<br \/>\n[03.038] (B) Disposed!<br \/>\n[04.049] (A) Destroyed!<br \/>\n[04.049] (A) Disposed!<\/code><\/p>\n<p>Now for some failure cases, starting with a single object:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate static async Task FailAsync(int failureStep)\r\n{\r\n    try\r\n    {\r\n        await AsyncEx.UsingAsync(\r\n            () =&gt; new MyObj(&quot;A&quot;, failureStep),\r\n            d =&gt; d.DoAsync());\r\n    }\r\n    catch (Exception e)\r\n    {\r\n        Console.WriteLine(e);\r\n    }\r\n\r\n    Console.WriteLine(&quot;----&quot;);\r\n}\r\n\r\nprivate static async Task FailureSampleAsync()\r\n{\r\n    \/\/ One object, fail on construction\r\n    await FailAsync(1);\r\n\r\n    \/\/ One object, fail on Do\r\n    await FailAsync(2);\r\n\r\n    \/\/ One object, fail on Destroy\r\n    await FailAsync(4);\r\n\r\n    \/\/ One object, fail on Do AND Destroy\r\n    await FailAsync(6);\r\n}\r\n<\/pre>\n<p>The output from the program, omitting a lot of the exception stacks to make it more readable:<br \/>\n<code>[00.001] (A) Failing (flag 1)!<br \/>\nSystem.InvalidOperationException: Failing (flag 1)!<br \/>\n----<br \/>\n[01.010] (A) Done!<br \/>\n[01.010] (A) Failing (flag 2)!<br \/>\n[02.030] (A) Destroyed!<br \/>\n[02.030] (A) Disposed!<br \/>\nSystem.AggregateException: One or more errors occurred.<br \/>\n(Inner Exception #0) System.InvalidOperationException: Failing (flag 2)!<br \/>\n----<br \/>\n[01.008] (A) Done!<br \/>\n[02.028] (A) Destroyed!<br \/>\n[02.028] (A) Failing (flag 4)!<br \/>\n[02.028] (A) Disposed!<br \/>\nSystem.AggregateException: One or more errors occurred.<br \/>\n(Inner Exception #0) System.InvalidOperationException: Failing (flag 4)!<br \/>\n----<br \/>\n[01.004] (A) Done!<br \/>\n[01.004] (A) Failing (flag 2)!<br \/>\n[02.014] (A) Destroyed!<br \/>\n[02.014] (A) Failing (flag 4)!<br \/>\n[02.014] (A) Disposed!<br \/>\nSystem.AggregateException: One or more errors occurred.<br \/>\n(Inner Exception #0) System.InvalidOperationException: Failing (flag 2)!<br \/>\n(Inner Exception #1) System.InvalidOperationException: Failing (flag 4)!<br \/>\n----<\/code><br \/>\nAs you can see, if construction succeeds, it immediately throws without further execution. Otherwise, DestroyAsync and Dispose will <em>always<\/em> be called, regardless of failures.<\/p>\n<p>Finally, let&#8217;s explore some failure cases with nested objects:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate static async Task Fail2Async(int failureStep1, int failureStep2)\r\n{\r\n    Func&lt;MyObj, MyObj, Task&gt; doBothAsync = async delegate(MyObj a, MyObj b)\r\n    {\r\n        await a.DoAsync();\r\n        await b.DoAsync();\r\n    };\r\n\r\n    try\r\n    {\r\n        await AsyncEx.UsingAsync(\r\n            () =&gt; new MyObj(&quot;A&quot;, failureStep1),\r\n            d1 =&gt; AsyncEx.UsingAsync(\r\n                () =&gt; new MyObj(&quot;B&quot;, failureStep2),\r\n                d2 =&gt; doBothAsync(d1, d2)));\r\n    }\r\n    catch (Exception e)\r\n    {\r\n        Console.WriteLine(e);\r\n    }\r\n\r\n    Console.WriteLine(&quot;----&quot;);\r\n}\r\n\r\nprivate static async Task FailureSample2Async()\r\n{\r\n    \/\/ Two objects, fail on construction of #2\r\n    await Fail2Async(0, 1);\r\n\r\n    \/\/ Two objects, fail on Do of #2\r\n    await Fail2Async(0, 2);\r\n\r\n    \/\/ Two objects, fail on Do of #1 and Destroy of #2\r\n    await Fail2Async(2, 4);\r\n\r\n    \/\/ Two objects, fail on Destroy of #1 and Do\/Destroy of #2\r\n    await Fail2Async(4, 6);\r\n}\r\n<\/pre>\n<p>And the (truncated) output, showing that any successfully constructed object is Destroyed\/Disposed regardless of other failures, with all exceptions aggregated at the end:<\/p>\n<p><code>[00.000] (B) Failing (flag 1)!<br \/>\n[01.015] (A) Destroyed!<br \/>\n[01.016] (A) Disposed!<br \/>\nSystem.AggregateException: One or more errors occurred.<br \/>\n(Inner Exception #0) System.InvalidOperationException: Failing (flag 1)!<br \/>\n----<br \/>\n[01.006] (A) Done!<br \/>\n[02.026] (B) Done!<br \/>\n[02.026] (B) Failing (flag 2)!<br \/>\n[03.036] (B) Destroyed!<br \/>\n[03.036] (B) Disposed!<br \/>\n[04.046] (A) Destroyed!<br \/>\n[04.046] (A) Disposed!<br \/>\nSystem.AggregateException: One or more errors occurred.<br \/>\n(Inner Exception #0) System.InvalidOperationException: Failing (flag 2)!<br \/>\n----<br \/>\n[01.011] (A) Done!<br \/>\n[01.012] (A) Failing (flag 2)!<br \/>\n[02.021] (B) Destroyed!<br \/>\n[02.022] (B) Failing (flag 4)!<br \/>\n[02.022] (B) Disposed!<br \/>\n[03.041] (A) Destroyed!<br \/>\n[03.042] (A) Disposed!<br \/>\nSystem.AggregateException: One or more errors occurred.<br \/>\n(Inner Exception #0) System.InvalidOperationException: Failing (flag 2)!<br \/>\n(Inner Exception #1) System.InvalidOperationException: Failing (flag 4)!<br \/>\n----<br \/>\n[01.019] (A) Done!<br \/>\n[02.029] (B) Done!<br \/>\n[02.029] (B) Failing (flag 2)!<br \/>\n[03.039] (B) Destroyed!<br \/>\n[03.039] (B) Failing (flag 4)!<br \/>\n[03.039] (B) Disposed!<br \/>\n[04.059] (A) Destroyed!<br \/>\n[04.059] (A) Failing (flag 4)!<br \/>\n[04.059] (A) Disposed!<br \/>\nSystem.AggregateException: One or more errors occurred.<br \/>\n(Inner Exception #0) System.InvalidOperationException: Failing (flag 4)!<br \/>\n(Inner Exception #1) System.InvalidOperationException: Failing (flag 2)!<br \/>\n(Inner Exception #2) System.InvalidOperationException: Failing (flag 4)!<br \/>\n----<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>It stands to reason that DisposeAsync would be the asynchronous counterpart of IDisposable.Dispose. However, I recommend that you do not use the Dispose pattern for asynchronous cleanup. Why not? First off, an async version of Dispose would not work properly&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[],"class_list":["post-641","post","type-post","status-publish","format-standard","hentry","category-async"],"_links":{"self":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/641","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=641"}],"version-history":[{"count":0,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/641\/revisions"}],"wp:attachment":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=641"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=641"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=641"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}