This repository was archived by the owner on Sep 8, 2025. It is now read-only.
File tree Expand file tree Collapse file tree 3 files changed +65
-4
lines changed
src/IdentityModel.AspNetCore.OAuth2Introspection/Infrastructure Expand file tree Collapse file tree 3 files changed +65
-4
lines changed Original file line number Diff line number Diff line change 6
6
7
7
namespace IdentityModel . AspNetCore . OAuth2Introspection . Infrastructure
8
8
{
9
- internal class AsyncLazy < T > : Lazy < Task < T > >
9
+ internal sealed class AsyncLazy < T >
10
10
{
11
- public AsyncLazy ( Func < Task < T > > taskFactory ) :
12
- base ( ( ) => Task . Factory . StartNew ( taskFactory ) . Unwrap ( ) )
13
- { }
11
+ private Lazy < Task < T > > _lazyTaskFactory ;
12
+ private readonly Func < Task < T > > _taskFactory ;
13
+ private readonly object _lazyInitializationGuard = new object ( ) ;
14
+
15
+ public AsyncLazy ( Func < Task < T > > taskFactory )
16
+ {
17
+ _taskFactory = taskFactory ;
18
+ _lazyTaskFactory = InitLazy ( _taskFactory ) ;
19
+ }
20
+
21
+ public Task < T > Value
22
+ {
23
+ get
24
+ {
25
+ //If the lazy value is not yet created, we should just return the lazy value (which will create it)
26
+ //If the value has been created and the value (which is a Task<T>) is not faulted, we should just return the value;
27
+ if ( ! ( _lazyTaskFactory . IsValueCreated && _lazyTaskFactory . Value . IsFaulted ) )
28
+ return _lazyTaskFactory . Value ;
29
+
30
+ lock ( _lazyInitializationGuard )
31
+ {
32
+ if ( _lazyTaskFactory . IsValueCreated && _lazyTaskFactory . Value . IsFaulted )
33
+ {
34
+ _lazyTaskFactory = InitLazy ( _taskFactory ) ;
35
+ }
36
+
37
+ return _lazyTaskFactory . Value ;
38
+ }
39
+ }
40
+ }
41
+
42
+ private static Lazy < Task < T > > InitLazy ( Func < Task < T > > taskFactory )
43
+ {
44
+ return new Lazy < Task < T > > ( ( ) => Task . Run ( taskFactory ) ) ;
45
+ }
14
46
}
15
47
}
Original file line number Diff line number Diff line change @@ -164,5 +164,27 @@ public async Task ActiveToken_With_SavedToken_And_Caching()
164
164
165
165
responseData . Should ( ) . Contain ( "token" , expectedToken ) ;
166
166
}
167
+
168
+ [ Fact ]
169
+ public async Task ActiveToken_With_Discovery_Unavailable_On_First_Request ( )
170
+ {
171
+ var handler = new DiscoveryEndpointHandler ( ) ;
172
+
173
+ var client = PipelineFactory . CreateClient ( ( o ) =>
174
+ {
175
+ _options ( o ) ;
176
+ o . DiscoveryHttpHandler = handler ;
177
+ o . IntrospectionHttpHandler = new IntrospectionEndpointHandler ( IntrospectionEndpointHandler . Behavior . Active ) ;
178
+ } ) ;
179
+
180
+ client . SetBearerToken ( "sometoken" ) ;
181
+
182
+ handler . IsFailureTest = true ;
183
+ await Assert . ThrowsAsync < InvalidOperationException > ( async ( ) => await client . GetAsync ( "http://test" ) ) ;
184
+
185
+ handler . IsFailureTest = false ;
186
+ var result = await client . GetAsync ( "http://test" ) ;
187
+ result . StatusCode . Should ( ) . Be ( HttpStatusCode . OK ) ;
188
+ }
167
189
}
168
190
}
Original file line number Diff line number Diff line change @@ -13,8 +13,15 @@ class DiscoveryEndpointHandler : HttpMessageHandler
13
13
{
14
14
public string Endpoint { get ; set ; }
15
15
16
+ public bool IsFailureTest { get ; set ; } = false ;
17
+
16
18
protected override Task < HttpResponseMessage > SendAsync ( HttpRequestMessage request , System . Threading . CancellationToken cancellationToken )
17
19
{
20
+ if ( IsFailureTest )
21
+ {
22
+ return Task . FromResult ( new HttpResponseMessage ( HttpStatusCode . NotFound ) ) ;
23
+ }
24
+
18
25
if ( request . RequestUri . AbsoluteUri . ToString ( ) == "https://authority.com/.well-known/openid-configuration" )
19
26
{
20
27
Endpoint = request . RequestUri . AbsoluteUri ;
You can’t perform that action at this time.
0 commit comments