1+ using System . Threading ;
2+ using Microsoft . Extensions . DependencyInjection ;
3+
4+ namespace Temporalio . Extensions . Hosting
5+ {
6+ /// <summary>
7+ /// Information and ability to control the activity DI scope.
8+ /// </summary>
9+ public static class ActivityScope
10+ {
11+ private static readonly AsyncLocal < IServiceScope ? > ServiceScopeLocal = new ( ) ;
12+ private static readonly AsyncLocal < object ? > ScopedInstanceLocal = new ( ) ;
13+
14+ /// <summary>
15+ /// Gets or sets the current scope for this activity.
16+ /// </summary>
17+ /// <remarks>
18+ /// This is backed by an async local. By default, when the activity invocation starts
19+ /// (meaning inside the interceptor, not before), a new service scope is created and set on
20+ /// this value. This means it will not be present in the primary execute-activity
21+ /// interceptor
22+ /// (<see cref="Worker.Interceptors.ActivityInboundInterceptor.ExecuteActivityAsync"/>) call
23+ /// but will be available everywhere else the ActivityExecutionContext is. When set by the
24+ /// internal code, it is also disposed by the internal code. See the next remark for how to
25+ /// control the scope.
26+ /// </remarks>
27+ /// <remarks>
28+ /// In situations where a user wants to control the service scope from the primary
29+ /// execute-activity interceptor, this can be set to the result of <c>CreateScope</c> or
30+ /// <c>CreateAsyncScope</c> of a service provider. The internal code will then use this
31+ /// instead of creating its own, and will therefore not dispose it. This should never be set
32+ /// anywhere but inside the primary execute-activity interceptor, and it no matter the value
33+ /// it will be set to null before the <c>base</c> call returns from the primary
34+ /// execute-activity interceptor.
35+ /// </remarks>
36+ public static IServiceScope ? ServiceScope
37+ {
38+ get => ServiceScopeLocal . Value ;
39+ set => ServiceScopeLocal . Value = value ;
40+ }
41+
42+ /// <summary>
43+ /// Gets or sets the scoped instance for non-static activity methods.
44+ /// </summary>
45+ /// <remarks>
46+ /// This is backed by an async local. By default, when the activity invocation starts
47+ /// (meaning inside the interceptor, not before) for a non-static method, an instance is
48+ /// obtained from the service provider and set on this value. This means it will not be
49+ /// present in the primary execute-activity interceptor
50+ /// (<see cref="Worker.Interceptors.ActivityInboundInterceptor.ExecuteActivityAsync"/>) call
51+ /// but will be available everywhere else the ActivityExecutionContext is. See the next
52+ /// remark for how to control the instance.
53+ /// </remarks>
54+ /// <remarks>
55+ /// In situations where a user wants to control the instance from the primary
56+ /// execute-activity interceptor, this can be set to the result of <c>GetRequiredService</c>
57+ /// of a service provider. The internal code will then use this instead of creating its own.
58+ /// This should never be set anywhere but inside the primary execute-activity interceptor,
59+ /// and it no matter the value it will be set to null before the <c>base</c> call returns
60+ /// from the primary execute-activity interceptor.
61+ /// </remarks>
62+ public static object ? ScopedInstance
63+ {
64+ get => ScopedInstanceLocal . Value ;
65+ set => ScopedInstanceLocal . Value = value ;
66+ }
67+ }
68+ }
0 commit comments