Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AsyncState can be used across different service providers #4966

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal sealed class AsyncState : IAsyncState
{
private static readonly AsyncLocal<AsyncStateHolder> _asyncContextCurrent = new();
private static readonly ObjectPool<List<object?>> _featuresPool = PoolFactory.CreatePool(new FeaturesPooledPolicy());
private int _contextCount;
private static int _contextCount;

public void Initialize()
{
Expand Down Expand Up @@ -104,7 +104,9 @@ internal static void EnsureCount(List<object?> features, int count)
}
}

#pragma warning disable CA1822
mobratil marked this conversation as resolved.
Show resolved Hide resolved
internal int ContextCount => Volatile.Read(ref _contextCount);
#pragma warning restore CA1822

private sealed class AsyncStateHolder
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using Xunit;

Check failure on line 1 in test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs

View check run for this annotation

Azure Pipelines / extensions-ci (Correctness WarningsCheck)

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs#L1

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs(1,1): error IDE0073: (NETCORE_ENGINEERING_TELEMETRY=Build) A source file is missing a required header. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0073)

Check failure on line 1 in test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs

View check run for this annotation

Azure Pipelines / extensions-ci (Correctness WarningsCheck)

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs#L1

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs(1,1): error IDE0073: (NETCORE_ENGINEERING_TELEMETRY=Build) A source file is missing a required header. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0073)

Check failure on line 1 in test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs

View check run for this annotation

Azure Pipelines / extensions-ci

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs#L1

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs(1,1): error IDE0073: (NETCORE_ENGINEERING_TELEMETRY=Build) A source file is missing a required header. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0073)

Check failure on line 1 in test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs

View check run for this annotation

Azure Pipelines / extensions-ci

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs#L1

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AssemblyInfo.cs(1,1): error IDE0073: (NETCORE_ENGINEERING_TELEMETRY=Build) A source file is missing a required header. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0073)
mobratil marked this conversation as resolved.
Show resolved Hide resolved

[assembly: CollectionBehavior(DisableTestParallelization = true)]
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ public class AsyncContextTests
public async Task CreateAsyncContext_BeforeInitialize()
{
var state = new AsyncState();
var initialContextCount = state.ContextCount;
var context1 = new AsyncContext<IThing>(state);
var context2 = new AsyncContext<IThing>(state);
var obj1 = new Thing();
var obj2 = new Thing();

Assert.Equal(2, state.ContextCount);
Assert.Equal(2, state.ContextCount - initialContextCount);
state.Initialize();

await Task.Run(() => context1.Set(obj1));
Expand All @@ -36,11 +37,12 @@ public async Task CreateAsyncContext_AfterInitialize()
{
var state = new AsyncState();
state.Initialize();
var initialContextCount = state.ContextCount;

var context1 = new AsyncContext<IThing>(state);
var context2 = new AsyncContext<IThing>(state);

Assert.Equal(2, state.ContextCount);
Assert.Equal(2, state.ContextCount - initialContextCount);

var obj1 = new Thing();

Expand All @@ -58,14 +60,14 @@ await Task.Run(() =>
public async Task CreateAsyncContext_BeforeAndAfterInitialize()
{
var state = new AsyncState();

var initialContextCount = state.ContextCount;
var context1 = new AsyncContext<IThing>(state);
state.Initialize();
var context2 = new AsyncContext<IThing>(state);
var obj1 = new Thing();
var obj2 = new Thing();

Assert.Equal(2, state.ContextCount);
Assert.Equal(2, state.ContextCount - initialContextCount);

await Task.Run(() =>
{
Expand All @@ -85,12 +87,13 @@ await Task.Run(() =>
public async Task Tryget_BeforeAndAfterInitialize()
{
var state = new AsyncState();
var initialContextCount = state.ContextCount;
var context1 = new AsyncContext<IThing>(state);
Assert.False(context1.TryGet(out _));
state.Initialize();
var obj1 = new Thing();

Assert.Equal(1, state.ContextCount);
Assert.Equal(1, state.ContextCount - initialContextCount);

await Task.Run(() =>
{
Expand All @@ -110,12 +113,12 @@ await Task.Run(() =>
public async Task CreateAsyncContextInAsync_AfterInitialize()
{
var state = new AsyncState();

var initialContextCount = state.ContextCount;
var context1 = new AsyncContext<IThing>(state);
var obj1 = new Thing();

state.Initialize();
Assert.Equal(1, state.ContextCount);
Assert.Equal(1, state.ContextCount - initialContextCount);

await Task.Run(async () =>
{
Expand Down Expand Up @@ -181,6 +184,7 @@ public void Reset_DoesNotDisposeObjects()
public async Task TwoAsyncFlows_WithDiffrentAsyncStates()
{
var state = new AsyncState();
var initialContextCount = state.ContextCount;

var task1 = Task.Run(async () =>
{
Expand Down Expand Up @@ -215,13 +219,14 @@ await Task.Run(async () =>
});

await Task.WhenAll(task1, task2);
Assert.Equal(2, state.ContextCount);
Assert.Equal(2, state.ContextCount - initialContextCount);
}

[Fact]
public async Task IndependentAsyncFlows_WithSameAsyncState()
{
var state = new AsyncState();
var initialContextCount = state.ContextCount;
var context = new AsyncContext<IThing>(state);

Func<Task?> setAsyncState = async () =>
Expand Down Expand Up @@ -251,6 +256,6 @@ await Task.Run(() =>

await Task.WhenAll(tasks);

Assert.Equal(1, state.ContextCount);
Assert.Equal(1, state.ContextCount - initialContextCount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace Microsoft.Extensions.AsyncState.Test;
Expand Down Expand Up @@ -195,15 +196,16 @@
public void RegisterContextCorrectly()
{
var asyncState = new AsyncState();
var initialContextCount = asyncState.ContextCount;

var c1 = asyncState.RegisterAsyncContext();
Assert.Equal(0, c1.Index);
Assert.Equal(0, c1.Index - initialContextCount);
var c2 = asyncState.RegisterAsyncContext();
Assert.Equal(1, c2.Index);
Assert.Equal(1, c2.Index - initialContextCount);
var c3 = asyncState.RegisterAsyncContext();
Assert.Equal(2, c3.Index);
Assert.Equal(2, c3.Index - initialContextCount);

Assert.Equal(3, asyncState.ContextCount);
Assert.Equal(3, asyncState.ContextCount - initialContextCount);
}

[Fact]
Expand All @@ -229,4 +231,23 @@
AsyncState.EnsureCount(l, 5);
Assert.Equal(5, l.Count);
}

[Fact]
public async Task AsyncStateCanBeUsedInDifferentServiceProviders()

Check failure on line 236 in test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs

View check run for this annotation

Azure Pipelines / extensions-ci (Correctness WarningsCheck)

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs#L236

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs(236,23): error S2699: (NETCORE_ENGINEERING_TELEMETRY=Build) Add at least one assertion to this test case. (https://rules.sonarsource.com/csharp/RSPEC-2699)

Check failure on line 236 in test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs

View check run for this annotation

Azure Pipelines / extensions-ci (Correctness WarningsCheck)

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs#L236

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs(236,23): error S2699: (NETCORE_ENGINEERING_TELEMETRY=Build) Add at least one assertion to this test case. (https://rules.sonarsource.com/csharp/RSPEC-2699)

Check failure on line 236 in test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs

View check run for this annotation

Azure Pipelines / extensions-ci

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs#L236

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs(236,23): error S2699: (NETCORE_ENGINEERING_TELEMETRY=Build) Add at least one assertion to this test case. (https://rules.sonarsource.com/csharp/RSPEC-2699)

Check failure on line 236 in test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs

View check run for this annotation

Azure Pipelines / extensions-ci

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs#L236

test/Libraries/Microsoft.Extensions.AsyncState.Tests/AsyncStateTests.cs(236,23): error S2699: (NETCORE_ENGINEERING_TELEMETRY=Build) Add at least one assertion to this test case. (https://rules.sonarsource.com/csharp/RSPEC-2699)
mobratil marked this conversation as resolved.
Show resolved Hide resolved
{
await using var spOne = PrepareAsyncState(new Tuple<double>(3.14));
await using var spTwo = PrepareAsyncState(new Tuple<int>(42));

_ = spOne.GetRequiredService<IAsyncContext<Tuple<double>>>().Get();
_ = spTwo.GetRequiredService<IAsyncContext<Tuple<double>>>().Get();

static ServiceProvider PrepareAsyncState<T>(T value)
where T : notnull
{
var services = new ServiceCollection().AddAsyncState().BuildServiceProvider();
services.GetRequiredService<IAsyncState>().Initialize();
services.GetRequiredService<IAsyncContext<T>>().Set(value);
return services;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
<Description>Unit tests for Microsoft.Extensions.AsyncState.</Description>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Libraries\Microsoft.Extensions.AsyncState\Microsoft.Extensions.AsyncState.csproj" ProjectUnderTest="true" />
</ItemGroup>
Expand Down