Skip to content

Commit

Permalink
Unify the documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
semihokur committed Jan 17, 2021
1 parent f63df2e commit c3dbeb2
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 48 deletions.
13 changes: 7 additions & 6 deletions AsyncFixer.Samples/NestedTaskToOuterTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ namespace AsyncFixer.Samples
{
class NestedTaskToOuterTask
{
async void main()
{
await Task.Factory.StartNew(() => foo());
}
// nested task can be unwrapped and awaited.
// For this scenario, overloads of Task.Run are provided
// to accept async functions and automatically unwrap the nested task

TaskCanceledException foo()
async Task foo()
{
return new TaskCanceledException();
Console.WriteLine("Hello");
await Task.Factory.StartNew(() => Task.Delay(1000));
Console.WriteLine("World");
}
}
}
2 changes: 1 addition & 1 deletion AsyncFixer.Vsix/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<ReleaseNotes>https://github.com/semihokur/AsyncFixer/blob/main/CHANGELOG.md</ReleaseNotes>
<Icon>icon.png</Icon>
<PreviewImage>preview.png</PreviewImage>
<Tags>asyncfixer analyzers async/await asynchronous concurrency diagnostics codefix roslyn codeanalysis async</Tags>
<Tags>asyncfixer analyzers async/await asynchronous concurrency diagnostics codefix roslyn codeanalysis async await</Tags>
</Metadata>
<Installation>
<InstallationTarget Version="[16.0,17.0)" Id="Microsoft.VisualStudio.Community" />
Expand Down
4 changes: 2 additions & 2 deletions AsyncFixer/AsyncFixer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<Authors>Semih Okur</Authors>
<Title>AsyncFixer: Advanced async/await Diagnostics and CodeFixes for C#</Title>
<Description>
AsyncFixer helps developers in finding and correcting common async/await *misuses* (i.e., anti-patterns). AsyncFixer has been tested with thousands of open-source C# apps and successfully handles many corner cases. It currently detects 5 common kinds of async/await misuses and fixes 3 of them via program transformations.
AsyncFixer helps developers in finding and correcting common async/await misuses (i.e., anti-patterns). It currently detects 5 common kinds of async/await misuses and fixes 3 of them via program transformations. AsyncFixer has been tested with thousands of open-source C# projects and successfully handles many corner cases.
</Description>
<PackageReleaseNotes>https://github.com/semihokur/AsyncFixer/blob/main/CHANGELOG.md</PackageReleaseNotes>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
Expand All @@ -22,7 +22,7 @@
<PackageIcon>icon.png</PackageIcon>
<RepositoryUrl>https://github.com/semihokur/AsyncFixer</RepositoryUrl>
<Copyright>Copyright (c) AsyncFixer 2015-2021</Copyright>
<PackageTags>asyncfixer analyzers async/await asynchronous concurrency diagnostics codefix roslyn codeanalysis async</PackageTags>
<PackageTags>asyncfixer analyzers async/await asynchronous concurrency diagnostics codefix roslyn codeanalysis async await</PackageTags>
<NoPackageAnalysis>false</NoPackageAnalysis>
<DevelopmentDependency>true</DevelopmentDependency>
</PropertyGroup>
Expand Down
65 changes: 62 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,65 @@
AsyncFixer helps developers in finding and correcting common async/await misuses. AsyncFixer was tested with hundreds of C# apps and successfully handles many corner cases.
AsyncFixer helps developers in finding and correcting common `async/await` *misuses* (i.e., anti-patterns). It currently detects 5 common kinds of async/await misuses and fixes 3 of them via program transformations. AsyncFixer has been tested with thousands of open-source C# projects and successfully handles many corner cases. It is also one of the most common analyzers used in C# projects from Microsoft.

AsyncFixer will work just in the IDE and work as an analyzer on every project you open in Visual Studio. It can also operate in batch mode to correct all misuses in the document, project, or solution. You can download the VSIX from here: https://visualstudiogallery.msdn.microsoft.com/03448836-db42-46b3-a5c7-5fc5d36a8308
AsyncFixer will work just in the IDE and work as an analyzer on every project you open in Visual Studio. It can also operate in batch mode to correct all misuses in the document, project, or solution. You can download the VSIX from [here](https://visualstudiogallery.msdn.microsoft.com/03448836-db42-46b3-a5c7-5fc5d36a8308).

If you want AsyncFixer to deploy as a NuGet package and work as a project-local analyzer that participates in builds, please also use the nuget package. Attaching an analyzer to a project means that the analyzer travels with the project to source control and so it's easy to apply the same rule for the team. You can download the nuget package from here: https://www.nuget.org/packages/AsyncFixer
If you want AsyncFixer to deploy as a NuGet package and work as a project-local analyzer that participates in builds, you can use the nuget package. Attaching an analyzer to a project means that the analyzer travels with the project to source control and so it is easy to apply the same rule for the team. You can download the nuget package from [here](https://www.nuget.org/packages/AsyncFixer).

Here are `async/await` *misuses* (i.e., anti-patterns) that AsyncFixer can currently detect:

### AsyncFixer01: Unnecessary async/await usage

There are some async methods where there is no need to use `async/await` keywords. It is important to detect this kind of misuse because adding the async modifier comes at a price. AsyncFixer automatically removes `async/await` keywords from those methods.

![asyncfixer-1.gif](https://raw.githubusercontent.com/semihokur/AsyncFixer/main/img/asyncfixer-1.gif)

### AsyncFixer02: Long-running or blocking operations inside an *async* method

Developers use some potentially long-running or blocking operations inside async methods even though there are corresponding asynchronous versions of these methods in .NET or third-party libraries. Some examples for such operations: `Task.Wait()`, `Task.Result`, `StreamReader.ReadToEnd()`, `Thread.Sleep()`, etc.

AsyncFixer automatically replaces those operations with their corresponding asynchronous operations and inserts an `await` expression. For instance, it converts `Thread.Sleep(...)` to `await Task.Delay(...)`.

![asyncfixer-2.gif](https://raw.githubusercontent.com/semihokur/AsyncFixer/main/img/asyncfixer-2.gif)

### AsyncFixer03: Fire & forget *async void* methods

Some async methods are 'fire & forget', which return `void`. Unless a method is only called as an event handler, it must be awaitable. Otherwise, it is a code smell because it complicates control flow and makes error detection & correction difficult.

AsyncFixer automatically converts `void` to `Task`.

![asyncfixer-3.gif](https://raw.githubusercontent.com/semihokur/AsyncFixer/main/img/asyncfixer-3.gif)

### AsyncFixer04: Fire & forget async call inside a *using* block

Inside a `using` block, developers insert a fire & forget async call which uses a disposable object as a parameter or target object. It can cause potential exceptions or wrong results. For instance, developers create a `Stream` in the `using` statement, pass it to the asynchronous method, and then `Stream` will be implicitly disposed via a `using` block. When the asynchronous method comes around to writing to `Stream`, it is (very likely) already disposed and you will have an exception.

### AsyncFixer05: Downcasting from a nested task to an outer task.

Downcasting from a nested task to a task or awaiting a nested task is dangerous. There is no way to wait for and get the result of the child task. This usually occurs when mixing `async/await` keywords with the old threading APIs such as `TaskFactory.StartNew`. Here is an example:

```
async Task foo()
{
Console.WriteLine("Hello");
await Task.Factory.StartNew(() => Task.Delay(1000)); // StartNew call returns a nested task: Task<Task>
Console.WriteLine("World");
}
```
A developer might expect one-second latency between "Hello" and "World" lines. However, those strings will be printed instantaneously without any latency. The reason is that we await a nested task, which is the return type of `StartNew` call. When we await the nested task, the return value is the inner task that is the result of `Task.Delay` call. As we do not await the inner task, we do not see the effect of the delay call. There are three possible fixes:

1. We can await the inner task as well:

```
await (await Task.Factory.StartNew(() => Task.Delay(1000)));
```

2. We can use `Unwrap` to expose the inner task to the `await` expression:

```
await Task.Factory.StartNew(() => Task.Delay(1000)).Unwrap();
```

3. If you do not have reasons to use `TaskFactory.StartNew` such as `TaskCreationOptions` and a custom `TaskScheduler`, we should always use `Task.Run` to automatically unwrap the inner task.

```
await Task.Run(() => Task.Delay(1000));
```
36 changes: 0 additions & 36 deletions docs/nugetDoc.md

This file was deleted.

File renamed without changes
File renamed without changes
File renamed without changes

0 comments on commit c3dbeb2

Please sign in to comment.