By default, tasks are started automatically when they are injected. It is recommended to use an argument of type CancellationToken to the composition root to be able to cancel the execution of a task. In this case, the composition root property is automatically converted to a method with a parameter of type CancellationToken. To start a task, an instance of type TaskFactory is used, with default settings:
- CancellationToken.None
- TaskScheduler.Default
- TaskCreationOptions.None
- TaskContinuationOptions.None
But you can always override them, as in the example below for TaskScheduler.Current.
interface IDependency
{
ValueTask DoSomething(CancellationToken cancellationToken);
}
class Dependency : IDependency
{
public ValueTask DoSomething(CancellationToken cancellationToken) => ValueTask.CompletedTask;
}
interface IService
{
Task RunAsync(CancellationToken cancellationToken);
}
class Service(Task<IDependency> dependencyTask) : IService
{
public async Task RunAsync(CancellationToken cancellationToken)
{
var dependency = await dependencyTask;
await dependency.DoSomething(cancellationToken);
}
}
DI.Setup(nameof(Composition))
.Hint(Hint.Resolve, "Off")
// Overrides TaskScheduler.Default if necessary
.Bind<TaskScheduler>().To(_ => TaskScheduler.Current)
// Specifies to use CancellationToken from the composition root argument,
// if not specified then CancellationToken.None will be used
.RootArg<CancellationToken>("cancellationToken")
.Bind<IDependency>().To<Dependency>()
.Bind<IService>().To<Service>()
// Composition root
.Root<IService>("GetRoot");
var composition = new Composition();
using var cancellationTokenSource = new CancellationTokenSource();
// Creates a composition root with the CancellationToken passed to it
var service = composition.GetRoot(cancellationTokenSource.Token);
await service.RunAsync(cancellationTokenSource.Token);
The following partial class will be generated:
partial class Composition
{
private readonly Composition _root;
[OrdinalAttribute(10)]
public Composition()
{
_root = this;
}
internal Composition(Composition parentScope)
{
_root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IService GetRoot(CancellationToken cancellationToken)
{
TaskScheduler transientTaskScheduler6 = TaskScheduler.Current;
TaskContinuationOptions transientTaskContinuationOptions5 = TaskContinuationOptions.None;
TaskCreationOptions transientTaskCreationOptions4 = TaskCreationOptions.None;
TaskFactory<IDependency> perBlockTaskFactory3;
CancellationToken localCancellationToken38 = cancellationToken;
TaskCreationOptions localTaskCreationOptions39 = transientTaskCreationOptions4;
TaskContinuationOptions localTaskContinuationOptions40 = transientTaskContinuationOptions5;
TaskScheduler localTaskScheduler41 = transientTaskScheduler6;
perBlockTaskFactory3 = new TaskFactory<IDependency>(localCancellationToken38, localTaskCreationOptions39, localTaskContinuationOptions40, localTaskScheduler41);
Func<IDependency> perBlockFunc2 = new Func<IDependency>([MethodImpl(MethodImplOptions.AggressiveInlining)] () =>
{
IDependency localValue42 = new Dependency();
return localValue42;
});
Task<IDependency> transientTask1;
// Injects an instance factory
Func<IDependency> localFactory43 = perBlockFunc2;
// Injects a task factory creating and scheduling task objects
TaskFactory<IDependency> localTaskFactory44 = perBlockTaskFactory3;
// Creates and starts a task using the instance factory
transientTask1 = localTaskFactory44.StartNew(localFactory43);
return new Service(transientTask1);
}
}
Class diagram:
classDiagram
class Composition {
<<partial>>
+IService GetRoot(System.Threading.CancellationToken cancellationToken)
}
class TaskCreationOptions
class TaskContinuationOptions
class TaskFactory
class TaskScheduler
class CancellationToken
Dependency --|> IDependency
class Dependency {
+Dependency()
}
Service --|> IService
class Service {
+Service(TaskᐸIDependencyᐳ dependencyTask)
}
class TaskᐸIDependencyᐳ
class FuncᐸIDependencyᐳ
class TaskFactoryᐸIDependencyᐳ
class IDependency {
<<interface>>
}
class IService {
<<interface>>
}
Composition ..> Service : IService GetRoot(System.Threading.CancellationToken cancellationToken)
TaskFactory o-- CancellationToken : Argument "cancellationToken"
TaskFactory *-- TaskCreationOptions : TaskCreationOptions
TaskFactory *-- TaskContinuationOptions : TaskContinuationOptions
TaskFactory *-- TaskScheduler : TaskScheduler
Service *-- TaskᐸIDependencyᐳ : TaskᐸIDependencyᐳ
TaskᐸIDependencyᐳ o-- "PerBlock" FuncᐸIDependencyᐳ : FuncᐸIDependencyᐳ
TaskᐸIDependencyᐳ o-- "PerBlock" TaskFactoryᐸIDependencyᐳ : TaskFactoryᐸIDependencyᐳ
FuncᐸIDependencyᐳ *-- Dependency : IDependency
TaskFactoryᐸIDependencyᐳ o-- CancellationToken : Argument "cancellationToken"
TaskFactoryᐸIDependencyᐳ *-- TaskCreationOptions : TaskCreationOptions
TaskFactoryᐸIDependencyᐳ *-- TaskContinuationOptions : TaskContinuationOptions
TaskFactoryᐸIDependencyᐳ *-- TaskScheduler : TaskScheduler