@@ -18,22 +18,19 @@ internal class FrameManager
1818
1919 private readonly ConcurrentDictionary < string , ExecutionContext > _contextIdToContext ;
2020 private readonly ILogger _logger ;
21- private readonly ConcurrentDictionary < string , Frame > _frames ;
22- private readonly AsyncDictionaryHelper < string , Frame > _asyncFrames ;
2321 private readonly List < string > _isolatedWorlds = new ( ) ;
22+ private readonly List < string > _frameNavigatedReceived = new ( ) ;
2423 private readonly TaskQueue _eventsQueue = new ( ) ;
2524 private bool _ensureNewDocumentNavigation ;
2625
2726 internal FrameManager ( CDPSession client , Page page , bool ignoreHTTPSErrors , TimeoutSettings timeoutSettings )
2827 {
2928 Client = client ;
3029 Page = page ;
31- _frames = new ConcurrentDictionary < string , Frame > ( ) ;
3230 _contextIdToContext = new ConcurrentDictionary < string , ExecutionContext > ( ) ;
3331 _logger = Client . Connection . LoggerFactory . CreateLogger < FrameManager > ( ) ;
3432 NetworkManager = new NetworkManager ( client , ignoreHTTPSErrors , this ) ;
3533 TimeoutSettings = timeoutSettings ;
36- _asyncFrames = new AsyncDictionaryHelper < string , Frame > ( _frames , "Frame {0} not found" ) ;
3734
3835 Client . MessageReceived += Client_MessageReceived ;
3936 }
@@ -54,12 +51,14 @@ internal FrameManager(CDPSession client, Page page, bool ignoreHTTPSErrors, Time
5451
5552 internal NetworkManager NetworkManager { get ; }
5653
57- internal Frame MainFrame { get ; set ; }
54+ internal Frame MainFrame => FrameTree . MainFrame ;
5855
5956 internal Page Page { get ; }
6057
6158 internal TimeoutSettings TimeoutSettings { get ; }
6259
60+ internal FrameTree FrameTree { get ; private set ; } = new ( ) ;
61+
6362 public async Task < IResponse > NavigateFrameAsync ( Frame frame , string url , NavigationOptions options )
6463 {
6564 var referrer = string . IsNullOrEmpty ( options . Referer )
@@ -129,7 +128,7 @@ await Task.WhenAll(
129128 getFrameTreeTask ,
130129 autoAttachTask ) . ConfigureAwait ( false ) ;
131130
132- await HandleFrameTreeAsync ( client , new FrameTree ( getFrameTreeTask . Result . FrameTree ) ) . ConfigureAwait ( false ) ;
131+ await HandleFrameTreeAsync ( client , getFrameTreeTask . Result . FrameTree ) . ConfigureAwait ( false ) ;
133132
134133 await Task . WhenAll (
135134 client . SendAsync ( "Page.setLifecycleEventsEnabled" , new PageSetLifecycleEventsEnabledRequest { Enabled = true } ) ,
@@ -173,21 +172,16 @@ internal void OnAttachedToTarget(TargetChangedArgs e)
173172 return ;
174173 }
175174
176- _frames . TryGetValue ( e . TargetInfo . TargetId , out var frame ) ;
177- if ( frame != null )
178- {
179- frame . UpdateClient ( e . Target . Session ) ;
180- }
175+ var frame = GetFrame ( e . TargetInfo . TargetId ) ;
176+ frame ? . UpdateClient ( e . Target . Session ) ;
181177
182178 e . Target . Session . MessageReceived += Client_MessageReceived ;
183179 _ = InitializeAsync ( e . Target . Session ) ;
184180 }
185181
186- internal Frame [ ] GetFrames ( ) => _frames . Values . ToArray ( ) ;
187-
188- internal Task < Frame > GetFrameAsync ( string frameId ) => _asyncFrames . GetItemAsync ( frameId ) ;
182+ internal Frame GetFrame ( string frameid ) => FrameTree . GetById ( frameid ) ;
189183
190- internal Task < Frame > TryGetFrameAsync ( string frameId ) => _asyncFrames . TryGetItemAsync ( frameId ) ;
184+ internal Frame [ ] GetFrames ( ) => FrameTree . Frames ;
191185
192186 private async Task NavigateAsync ( CDPSession client , string url , string referrer , string frameId )
193187 {
@@ -266,15 +260,14 @@ private void Client_MessageReceived(object sender, MessageEventArgs e)
266260
267261 private void OnFrameStartedLoading ( BasicFrameResponse e )
268262 {
269- if ( _frames . TryGetValue ( e . FrameId , out var frame ) )
270- {
271- frame . OnLoadingStarted ( ) ;
272- }
263+ var frame = GetFrame ( e . FrameId ) ;
264+ frame ? . OnLoadingStarted ( ) ;
273265 }
274266
275267 private void OnFrameStoppedLoading ( BasicFrameResponse e )
276268 {
277- if ( _frames . TryGetValue ( e . FrameId , out var frame ) )
269+ var frame = GetFrame ( e . FrameId ) ;
270+ if ( frame != null )
278271 {
279272 frame . OnLoadingStopped ( ) ;
280273 LifecycleEvent ? . Invoke ( this , new FrameEventArgs ( frame ) ) ;
@@ -283,7 +276,8 @@ private void OnFrameStoppedLoading(BasicFrameResponse e)
283276
284277 private void OnLifeCycleEvent ( LifecycleEventResponse e )
285278 {
286- if ( _frames . TryGetValue ( e . FrameId , out var frame ) )
279+ var frame = GetFrame ( e . FrameId ) ;
280+ if ( frame != null )
287281 {
288282 frame . OnLifecycleEvent ( e . LoaderId , e . Name ) ;
289283 LifecycleEvent ? . Invoke ( this , new FrameEventArgs ( frame ) ) ;
@@ -318,7 +312,7 @@ private void OnExecutionContextDestroyed(int contextId, CDPSession session)
318312 private async Task OnExecutionContextCreatedAsync ( ContextPayload contextPayload , CDPSession session )
319313 {
320314 var frameId = contextPayload . AuxData ? . FrameId ;
321- var frame = ! string . IsNullOrEmpty ( frameId ) ? await GetFrameAsync ( frameId ) . ConfigureAwait ( false ) : null ;
315+ var frame = ! string . IsNullOrEmpty ( frameId ) ? await FrameTree . GetFrameAsync ( frameId ) . ConfigureAwait ( false ) : null ;
322316 IsolatedWorld world = null ;
323317
324318 if ( frame != null )
@@ -350,7 +344,8 @@ private async Task OnExecutionContextCreatedAsync(ContextPayload contextPayload,
350344
351345 private void OnFrameDetached ( PageFrameDetachedResponse e )
352346 {
353- if ( _frames . TryGetValue ( e . FrameId , out var frame ) )
347+ var frame = GetFrame ( e . FrameId ) ;
348+ if ( frame != null )
354349 {
355350 if ( e . Reason == FrameDetachedReason . Remove )
356351 {
@@ -365,17 +360,21 @@ private void OnFrameDetached(PageFrameDetachedResponse e)
365360
366361 private async Task OnFrameNavigatedAsync ( FramePayload framePayload )
367362 {
363+ // This is in the event handler upstream.
364+ // It's more consistent having this here.
365+ _frameNavigatedReceived . Add ( framePayload . Id ) ;
366+
368367 var isMainFrame = string . IsNullOrEmpty ( framePayload . ParentId ) ;
369- var frame = isMainFrame ? MainFrame : await GetFrameAsync ( framePayload . Id ) . ConfigureAwait ( false ) ;
368+ var frame = isMainFrame ? MainFrame : await FrameTree . GetFrameAsync ( framePayload . Id ) . ConfigureAwait ( false ) ;
370369
371370 Contract . Assert ( isMainFrame || frame != null , "We either navigate top level or have old version of the navigated frame" ) ;
372371
373372 // Detach all child frames first.
374373 if ( frame != null )
375374 {
376- while ( frame . ChildFrames . Count > 0 )
375+ while ( frame . ChildFrames . Any ( ) )
377376 {
378- RemoveFramesRecursively ( frame . ChildFrames [ 0 ] ) ;
377+ RemoveFramesRecursively ( frame . ChildFrames . First ( ) as Frame ) ;
379378 }
380379 }
381380
@@ -384,22 +383,16 @@ private async Task OnFrameNavigatedAsync(FramePayload framePayload)
384383 {
385384 if ( frame != null )
386385 {
387- // Update frame id to retain frame identity on cross-process navigation.
388- if ( frame . Id != null )
389- {
390- _frames . TryRemove ( frame . Id , out _ ) ;
391- }
392-
386+ FrameTree . RemoveFrame ( frame ) ;
393387 frame . Id = framePayload . Id ;
394388 }
395389 else
396390 {
397391 // Initial main frame navigation.
398- frame = new Frame ( this , null , framePayload . Id , Client ) ;
392+ frame = new Frame ( this , framePayload . Id , null , Client ) ;
399393 }
400394
401- _asyncFrames . AddItem ( framePayload . Id , frame ) ;
402- MainFrame = frame ;
395+ FrameTree . AddFrame ( frame ) ;
403396 }
404397
405398 // Update frame payload.
@@ -410,7 +403,8 @@ private async Task OnFrameNavigatedAsync(FramePayload framePayload)
410403
411404 private void OnFrameNavigatedWithinDocument ( NavigatedWithinDocumentResponse e )
412405 {
413- if ( _frames . TryGetValue ( e . FrameId , out var frame ) )
406+ var frame = GetFrame ( e . FrameId ) ;
407+ if ( frame != null )
414408 {
415409 frame . NavigatedWithinDocument ( e . Url ) ;
416410
@@ -420,15 +414,15 @@ private void OnFrameNavigatedWithinDocument(NavigatedWithinDocumentResponse e)
420414 }
421415 }
422416
423- private void RemoveFramesRecursively ( IFrame frame )
417+ private void RemoveFramesRecursively ( Frame frame )
424418 {
425- while ( frame . ChildFrames . Count > 0 )
419+ while ( frame . ChildFrames . Any ( ) )
426420 {
427- RemoveFramesRecursively ( frame . ChildFrames [ 0 ] ) ;
421+ RemoveFramesRecursively ( frame . ChildFrames . First ( ) as Frame ) ;
428422 }
429423
430- ( ( Frame ) frame ) . Detach ( ) ;
431- _frames . TryRemove ( frame . Id , out _ ) ;
424+ frame . Detach ( ) ;
425+ FrameTree . RemoveFrame ( frame ) ;
432426 FrameDetached ? . Invoke ( this , new FrameEventArgs ( frame ) ) ;
433427 }
434428
@@ -437,37 +431,41 @@ private void OnFrameAttached(CDPSession session, PageFrameAttachedResponse frame
437431
438432 private void OnFrameAttached ( CDPSession session , string frameId , string parentFrameId )
439433 {
440- if ( _frames . TryGetValue ( frameId , out var existingFrame ) )
434+ var frame = GetFrame ( frameId ) ;
435+ if ( frame != null )
441436 {
442- if ( session != null && existingFrame . IsOopFrame )
437+ if ( session != null && frame . IsOopFrame )
443438 {
444- existingFrame . UpdateClient ( session ) ;
439+ frame . UpdateClient ( session ) ;
445440 }
446441
447442 return ;
448443 }
449444
450- if ( ! _frames . ContainsKey ( frameId ) && _frames . ContainsKey ( parentFrameId ) )
451- {
452- var parentFrame = _frames [ parentFrameId ] ;
453- var frame = new Frame ( this , parentFrame , frameId , session ) ;
454- _asyncFrames . AddItem ( frame . Id , frame ) ;
455- FrameAttached ? . Invoke ( this , new FrameEventArgs ( frame ) ) ;
456- }
445+ frame = new Frame ( this , frameId , parentFrameId , session ) ;
446+ FrameTree . AddFrame ( frame ) ;
447+ FrameAttached ? . Invoke ( this , new FrameEventArgs ( frame ) ) ;
457448 }
458449
459- private async Task HandleFrameTreeAsync ( CDPSession session , FrameTree frameTree )
450+ private async Task HandleFrameTreeAsync ( CDPSession session , PageGetFrameTree frameTree )
460451 {
461452 if ( ! string . IsNullOrEmpty ( frameTree . Frame . ParentId ) )
462453 {
463454 OnFrameAttached ( session , frameTree . Frame . Id , frameTree . Frame . ParentId ) ;
464455 }
465456
466- await OnFrameNavigatedAsync ( frameTree . Frame ) . ConfigureAwait ( false ) ;
457+ if ( ! _frameNavigatedReceived . Contains ( frameTree . Frame . Id ) )
458+ {
459+ await OnFrameNavigatedAsync ( frameTree . Frame ) . ConfigureAwait ( false ) ;
460+ }
461+ else
462+ {
463+ _frameNavigatedReceived . Remove ( frameTree . Frame . Id ) ;
464+ }
467465
468- if ( frameTree . Childs != null )
466+ if ( frameTree . ChildFrames != null )
469467 {
470- foreach ( var child in frameTree . Childs )
468+ foreach ( var child in frameTree . ChildFrames )
471469 {
472470 await HandleFrameTreeAsync ( session , child ) . ConfigureAwait ( false ) ;
473471 }
0 commit comments