Skip to content

Instantly share code, notes, and snippets.

@dcomartin
Created July 14, 2020 00:08
Show Gist options
  • Save dcomartin/43bf92f004e79700f2bd4a2fe7223ca0 to your computer and use it in GitHub Desktop.
Save dcomartin/43bf92f004e79700f2bd4a2fe7223ca0 to your computer and use it in GitHub Desktop.
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Xunit;
namespace Tests
{
public class ScopedLifetimeTest
{
[Fact]
public async Task ShouldShitTheBed()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<ClassA>();
serviceCollection.AddScoped<ClassB>();
serviceCollection.AddScoped<ClassC>();
var provider = serviceCollection.BuildServiceProvider();
var classA = provider.GetService<ClassA>();
var result = await classA.DoWork();
// This bombs because ClassB changes the value to 0 before ClassC finishes
result.ShouldBe(4);
}
}
public class ClassA
{
private readonly ClassB _classB;
private readonly ClassC _classC;
public ClassA(ClassB classB, ClassC classC)
{
_classB = classB;
_classC = classC;
}
public async Task<int> DoWork()
{
var taskC = _classC.NotThreadSafe("test");
// As a consumer, you don't know that class B even uses Class C.
var taskB = _classB.DoWork();
await Task.WhenAll(taskB, taskC);
return await taskC;
}
}
public class ClassB
{
private readonly ClassC _classC;
public ClassB(ClassC classC)
{
_classC = classC;
}
public async Task<int> DoWork()
{
return await _classC.NotThreadSafe("");
}
}
// If using Scoped lifetime, then by default you must also make everything thread-safe
public class ClassC
{
private string? _state;
public async Task<int> NotThreadSafe(string state)
{
_state = state;
// Delay this Task so we can end up having ClassB change the state before we return the length
if (state.Length > 0)
{
await Task.Delay(10);
}
return _state.Length;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment