Skip to content

Commit 75ca142

Browse files
committed
Updated documentation for asynchronous services
1 parent 1e59884 commit 75ca142

9 files changed

Lines changed: 258 additions & 26 deletions

src/Documentation/AdditionalReferenceDocumentation.shfbproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
<DocumentationSource sourceFile="..\packages\Newtonsoft.Json.5.0.8\lib\net40\Newtonsoft.Json.xml" />
3232
<DocumentationSource sourceFile="..\packages\SimpleRESTServices.1.3.0.1\lib\net40\SimpleRESTServices.dll" />
3333
<DocumentationSource sourceFile="..\packages\SimpleRESTServices.1.3.0.1\lib\net40\SimpleRESTServices.xml" />
34+
<DocumentationSource sourceFile="..\packages\Rackspace.Threading.1.1.0-beta001\lib\net40-client\Rackspace.Threading.dll" />
35+
<DocumentationSource sourceFile="..\packages\Rackspace.Threading.1.1.0-beta001\lib\net40-client\Rackspace.Threading.xml" />
3436
</DocumentationSources>
3537
</PropertyGroup>
3638
<!-- There are no properties for these groups. AnyCPU needs to appear in order for Visual Studio to perform

src/Documentation/Content/AsynchronousServices.aml

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,9 @@
66

77
<introduction>
88
<para>
9-
The openstack.net SDK is migrating to an asynchronous service model using the
10-
<externalLink>
11-
<linkText>Task-based Asynchronous Pattern (TAP)</linkText>
12-
<linkAlternateText>Task-based Asynchronous Pattern (TAP) (Microsoft Developer Network)</linkAlternateText>
13-
<linkUri>http://msdn.microsoft.com/en-us/library/hh873175.aspx</linkUri>
14-
</externalLink>
15-
for ongoing feature support.
16-
This page contains information about several aspects of the asynchronous interfaces which could
17-
result in some confusion during development. It also describes the inclusion of extension methods
9+
The openstack.net SDK is migrating to an asynchronous service model using the <token>TaskBasedAsync</token>
10+
for ongoing feature support. This page contains information about several aspects of the asynchronous interfaces
11+
which could result in some confusion during development. It also describes the inclusion of extension methods
1812
that allow new product features to be used in code that is not allowed to make asynchronous API
1913
calls.
2014
</para>
@@ -33,12 +27,8 @@
3327
<para>
3428
The Task Parallel Library is used extensively by the implementation of this SDK. The library was
3529
originally added as part of .NET 4, users still working with .NET 3.5 make use of the
36-
<externalLink>
37-
<linkText>Task Parallel Library for .NET 3.5</linkText>
38-
<linkUri>http://www.nuget.org/packages/TaskParallelLibrary/</linkUri>
39-
</externalLink>
40-
package using NuGet. This package is automatically installed by NuGet when the SDK package is
41-
added to a project targeting .NET 3.5.
30+
<token>TaskParallelLibrary35</token> package using NuGet. This package is automatically installed by NuGet
31+
when the SDK package is added to a project targeting .NET 3.5.
4232
</para>
4333
<para>
4434
Language support varies by language. The following table shows the language features available
@@ -182,6 +172,14 @@
182172
project file.
183173
</para>
184174
<code language="xml">&lt;UseHostCompilerIfAvailable&gt;false&lt;/UseHostCompilerIfAvailable&gt;</code>
175+
<alert class="important">
176+
<para>
177+
While the <codeInline>UseHostCompilerIfAvailable</codeInline> setting allows Visual Studio 2010 to
178+
compile C# and Visual Basic projects using <token>AsyncAwait</token>, the editor itself does not
179+
recognize these keywords. As a result, some functionality including but not limited to IntelliSense may
180+
not function if this option is used.
181+
</para>
182+
</alert>
185183
</content>
186184
</section>
187185
</sections>
@@ -193,11 +191,15 @@
193191
<para>
194192
Asynchronous methods are capable of throwing exceptions before creating a
195193
<codeEntityReference>T:System.Threading.Tasks.Task</codeEntityReference> or during the asynchronous
196-
execution of the task itself. The asynchronous service interfaces do not distinguish between these
194+
execution of the task itself. The documentation for asynchronous methods does not distinguish between these
197195
two cases, allowing for any of the specified exceptions to be thrown in either manner.
198196
</para>
199-
<list class="bullet">
200-
<listItem>
197+
</content>
198+
199+
<sections>
200+
<section>
201+
<title>Exceptions Prior to Task Creation</title>
202+
<content>
201203
<para>
202204
Exceptions thrown prior to the creation of the
203205
<codeEntityReference>T:System.Threading.Tasks.Task</codeEntityReference> object representing the
@@ -207,8 +209,14 @@
207209
<codeEntityReference>T:System.ArgumentNullException</codeEntityReference> or
208210
<codeEntityReference>T:System.ArgumentException</codeEntityReference> to handle the exception.
209211
</para>
210-
</listItem>
211-
<listItem>
212+
<code language="cs" region="ExceptionPriorToTaskCreation" source="..\Samples\CSharpCodeSamples\AsynchronousExceptionsExamples.cs"/>
213+
<code language="vb" region="ExceptionPriorToTaskCreation" source="..\Samples\VBCodeSamples\AsynchronousExceptionsExamples.vb"/>
214+
</content>
215+
</section>
216+
217+
<section>
218+
<title>Exceptions During Task Execution</title>
219+
<content>
212220
<para>
213221
Exceptions thrown during the asynchronous execution of the task are wrapped in an
214222
<codeEntityReference>T:System.AggregateException</codeEntityReference> object and returned by the
@@ -220,9 +228,54 @@
220228
property within an exception handling block that includes a handler for
221229
<codeEntityReference>T:System.AggregateException</codeEntityReference>.
222230
</para>
223-
</listItem>
224-
</list>
225-
</content>
231+
<para>
232+
This library additionally ensures that exceptions thrown by asynchronous operations are not wrapped in
233+
multiple layers of <codeEntityReference>T:System.AggregateException</codeEntityReference>. In other words,
234+
an <codeEntityReference>T:System.AggregateException</codeEntityReference> thrown during the asynchronous
235+
execution of a task will result in the
236+
<codeEntityReference>P:System.Threading.Tasks.Task.Exception</codeEntityReference> property returning an
237+
<codeEntityReference>T:System.AggregateException</codeEntityReference> with exactly one inner exception,
238+
which is the original <codeEntityReference>T:System.ArgumentException</codeEntityReference>. This
239+
guarantee simplifies the use of the API is languages that support <token>AsyncAwait</token>, since those
240+
operators automatically unwrap the first layer of
241+
<codeEntityReference>T:System.AggregateException</codeEntityReference>.
242+
</para>
243+
<code language="cs" region="ExceptionDuringTaskExecution" source="..\Samples\CSharpCodeSamples\AsynchronousExceptionsExamples.cs"/>
244+
<code language="vb" region="ExceptionDuringTaskExecution" source="..\Samples\VBCodeSamples\AsynchronousExceptionsExamples.vb"/>
245+
</content>
246+
</section>
247+
248+
<section>
249+
<title>Consistent Exception Handling</title>
250+
<content>
251+
<para>
252+
Applications implementing specialized handling for exception which occur during asynchronous calls have
253+
multiple options available for consistent handling. The simplest solution, when available, involves using
254+
<token>AsyncAwait</token>. These operators automatically unwrap the first exception instance in the
255+
<codeEntityReference>P:System.AggregateException.InnerExceptions</codeEntityReference> collection of an
256+
<codeEntityReference>T:System.AggregateException</codeEntityReference>, resulting in behavior that appears
257+
to calling code as though the exception was directly thrown by the invoked method. The second method
258+
involves treating the original call as a continuation of another task, ensuring that all exceptions are
259+
presented as an <codeEntityReference>T:System.AggregateException</codeEntityReference> to the exception
260+
handling code. The following code shows the application of this strategy to an existing asynchronous call.
261+
Note that the <codeEntityReference>T:Rackspace.Threading.CompletedTask</codeEntityReference> class and
262+
<codeEntityReference>Overload:Rackspace.Threading.CoreTaskExtensions.Then</codeEntityReference>
263+
extension method are part of the <token>RackspaceThreadingLibrary</token> separately from this SDK.
264+
</para>
265+
<code language="cs" region="AsynchronousMethodAsContinuation" source="..\Samples\CSharpCodeSamples\AsynchronousExceptionsExamples.cs"/>
266+
<code language="vb" region="AsynchronousMethodAsContinuation" source="..\Samples\VBCodeSamples\AsynchronousExceptionsExamples.vb"/>
267+
<para>
268+
Code using the continuation strategy for consistent error handling may benefit from the use of the
269+
<codeEntityReference>Overload:Rackspace.Threading.CoreTaskExtensions.Catch</codeEntityReference> methods,
270+
which are also part of the <token>RackspaceThreadingLibrary</token>. This extension method behaves in a
271+
manner similar to <token>Await</token>, automatically unwrapping the first exception instance in the
272+
<codeEntityReference>P:System.AggregateException.InnerExceptions</codeEntityReference> collection
273+
of an <codeEntityReference>T:System.AggregateException</codeEntityReference> before invoking the
274+
continuation function which handles the exception.
275+
</para>
276+
</content>
277+
</section>
278+
</sections>
226279
</section>
227280

228281
<section address="SynchronousExtensions">

src/Documentation/SharedTokens.tokens

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
xmlns:xlink="http://www.w3.org/1999/xlink">
55

66
<!--
7-
The following items can only be used in <token> elements that appear in the XML documentation comments.
7+
The following items can only be used in <token> elements that appear in the **XML documentation comments**.
88
-->
99

10-
<item id="TaskParallelLibrary">
10+
<item id="SeeTaskParallelLibrary">
1111
<see href="http://msdn.microsoft.com/en-us/library/dd460717.aspx">Task Parallel Library</see>
1212
</item>
1313

@@ -22,8 +22,39 @@
2222

2323
<item id="TplExample">
2424
<para>
25-
The following code shows demonstrates the same example using the <token>TaskParallelLibrary</token>
25+
The following code shows demonstrates the same example using the <token>SeeTaskParallelLibrary</token>
2626
instead of the <see langword="async/await"/> operators.
2727
</para>
2828
</item>
29+
30+
<!--
31+
The following items can only be used in <token> elements that appear in **MAML topics**.
32+
-->
33+
34+
<item id="TaskBasedAsync"><ddue:externalLink>
35+
<ddue:linkText>Task-based Asynchronous Pattern (TAP)</ddue:linkText>
36+
<ddue:linkAlternateText>Task-based Asynchronous Pattern (TAP) (Microsoft Developer Network)</ddue:linkAlternateText>
37+
<ddue:linkUri>http://msdn.microsoft.com/en-us/library/hh873175.aspx</ddue:linkUri>
38+
</ddue:externalLink></item>
39+
40+
<item id="TaskParallelLibrary"><ddue:externalLink>
41+
<ddue:linkText>Task Parallel Library</ddue:linkText>
42+
<ddue:linkUri>http://msdn.microsoft.com/en-us/library/dd460717.aspx</ddue:linkUri>
43+
</ddue:externalLink></item>
44+
45+
<item id="TaskParallelLibrary35"><ddue:externalLink>
46+
<ddue:linkText>Task Parallel Library for .NET 3.5</ddue:linkText>
47+
<ddue:linkUri>http://www.nuget.org/packages/TaskParallelLibrary/</ddue:linkUri>
48+
</ddue:externalLink></item>
49+
50+
<item id="RackspaceThreadingLibrary"><ddue:externalLink>
51+
<ddue:linkText>Rackspace Threading Library</ddue:linkText>
52+
<ddue:linkUri>https://github.com/rackerlabs/dotnet-threading</ddue:linkUri>
53+
</ddue:externalLink></item>
54+
55+
<item id="Async"><ddue:markup><span class="keyword">async</span></ddue:markup></item>
56+
57+
<item id="Await"><ddue:markup><span class="keyword">await</span></ddue:markup></item>
58+
59+
<item id="AsyncAwait"><ddue:markup><span class="keyword">async</span>/<span class="keyword">await</span></ddue:markup></item>
2960
</content>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
namespace CSharpCodeSamples
2+
{
3+
using System;
4+
using System.Threading.Tasks;
5+
using Rackspace.Threading;
6+
7+
public class AsynchronousExceptionsExamples
8+
{
9+
public void ExceptionPriorToTaskCreation()
10+
{
11+
#region ExceptionPriorToTaskCreation
12+
try
13+
{
14+
Task myTask = SomeOperationAsync();
15+
}
16+
catch (ArgumentException ex)
17+
{
18+
// ex was thrown directly by SomeOperationAsync. If SomeOperationAsync is marked with the `async`
19+
// keyword, then ex was thrown prior to the first use of the `await` keyword within the implementation.
20+
}
21+
#endregion
22+
}
23+
24+
public void ExceptionDuringTaskExecution()
25+
{
26+
#region ExceptionDuringTaskExecution
27+
try
28+
{
29+
Task myTask = SomeOperationAsync();
30+
}
31+
catch (AggregateException wrapperEx)
32+
{
33+
ArgumentException ex = wrapperEx.InnerException as ArgumentException;
34+
if (ex == null)
35+
throw;
36+
37+
// ex was thrown during the asynchronous portion of SomeOperationAsync. If SomeOperationAsync is marked
38+
// with the `async` keyword, then ex was thrown after the first use of the `await` keyword within the
39+
// method.
40+
}
41+
#endregion
42+
}
43+
44+
public void AsynchronousMethodAsContinuation()
45+
{
46+
#region AsynchronousMethodAsContinuation
47+
// original asynchronous method invocation
48+
Task task1 = SomeOperationAsync();
49+
50+
// method invocation treated as a continuation
51+
Task task2 = CompletedTask.Default.Then(_ => SomeOperationAsync());
52+
#endregion
53+
}
54+
55+
private static Task SomeOperationAsync()
56+
{
57+
throw new NotSupportedException();
58+
}
59+
}
60+
}

src/Samples/CSharpCodeSamples/CSharpCodeSamples.csproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1313
<FileAlignment>512</FileAlignment>
1414
<TargetFrameworkProfile />
15+
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
16+
<RestorePackages>true</RestorePackages>
1517
</PropertyGroup>
1618
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
1719
<DebugSymbols>true</DebugSymbols>
@@ -33,6 +35,9 @@
3335
<Prefer32Bit>false</Prefer32Bit>
3436
</PropertyGroup>
3537
<ItemGroup>
38+
<Reference Include="Rackspace.Threading">
39+
<HintPath>..\..\packages\Rackspace.Threading.1.1.0-beta001\lib\net45\Rackspace.Threading.dll</HintPath>
40+
</Reference>
3641
<Reference Include="System" />
3742
<Reference Include="System.Core" />
3843
<Reference Include="System.Xml.Linq" />
@@ -42,6 +47,7 @@
4247
<Reference Include="System.Xml" />
4348
</ItemGroup>
4449
<ItemGroup>
50+
<Compile Include="AsynchronousExceptionsExamples.cs" />
4551
<Compile Include="ObjectStorageProviderExamples.cs" />
4652
<Compile Include="Properties\AssemblyInfo.cs" />
4753
<Compile Include="QueueingServiceExamples.cs" />
@@ -52,7 +58,17 @@
5258
<Name>corelib.v4.0</Name>
5359
</ProjectReference>
5460
</ItemGroup>
61+
<ItemGroup>
62+
<None Include="packages.CSharpCodeSamples.config" />
63+
</ItemGroup>
5564
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
65+
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
66+
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
67+
<PropertyGroup>
68+
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
69+
</PropertyGroup>
70+
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
71+
</Target>
5672
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
5773
Other similar extension points exist, see Microsoft.Common.targets.
5874
<Target Name="BeforeBuild">
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Rackspace.Threading" version="1.1.0-beta001" targetFramework="net45" />
4+
</packages>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
Imports System.Threading.Tasks
2+
Imports Rackspace.Threading
3+
4+
Public Class AsynchronousExceptionsExamples
5+
6+
Public Sub ExceptionPriorToTaskCreation()
7+
' #Region ExceptionPriorToTaskCreation
8+
Try
9+
Dim myTask As Task = SomeOperationAsync()
10+
Catch ex As ArgumentException
11+
' ex was thrown directly by SomeOperationAsync. If SomeOperationAsync Is marked with the `Async`
12+
' keyword, then ex was thrown prior to the first use of the `Await` keyword within the implementation.
13+
End Try
14+
' #End Region
15+
End Sub
16+
17+
Public Sub ExceptionDuringTaskExecution()
18+
' #Region ExceptionDuringTaskExecution
19+
Try
20+
Dim myTask As Task = SomeOperationAsync()
21+
Catch wrapperEx As AggregateException
22+
Dim ex = TryCast(wrapperEx.InnerException, ArgumentException)
23+
If ex Is Nothing Then
24+
Throw
25+
End If
26+
27+
' ex was thrown during the asynchronous portion of SomeOperationAsync. If SomeOperationAsync Is marked
28+
' with the `Async` keyword, then ex was thrown after the first use of the `Await` keyword within the
29+
' method.
30+
End Try
31+
' #End Region
32+
End Sub
33+
34+
Public Sub AsynchronousMethodAsContinuation()
35+
' #Region AsynchronousMethodAsContinuation
36+
' original asynchronous method invocation
37+
Dim task1 = SomeOperationAsync()
38+
39+
' method invocation treated as a continuation
40+
Dim task2 = CompletedTask.Default.Then(Function(task) SomeOperationAsync())
41+
' #End Region
42+
End Sub
43+
44+
Public Function SomeOperationAsync() As Task
45+
Throw New NotSupportedException()
46+
End Function
47+
48+
End Class

0 commit comments

Comments
 (0)