@@ -6,70 +6,97 @@ import { OutOfProcessRenderBatch } from './Rendering/RenderBatch/OutOfProcessRen
6
6
import { internalFunctions as uriHelperFunctions } from './Services/UriHelper' ;
7
7
import { renderBatch } from './Rendering/Renderer' ;
8
8
import { fetchBootConfigAsync , loadEmbeddedResourcesAsync } from './BootCommon' ;
9
+ import { CircuitHandler } from './Platform/Circuits/CircuitHandler' ;
9
10
10
- let connection : signalR . HubConnection ;
11
+ async function boot ( reconnect : boolean = false ) {
12
+ const circuitHandlers = new Array < CircuitHandler > ( ) ;
13
+ window [ 'Blazor' ] . addCircuitHandler = ( circuitHandler : CircuitHandler ) => circuitHandlers . push ( circuitHandler ) ;
11
14
12
- function boot ( ) {
13
- // In the background, start loading the boot config and any embedded resources
14
- const embeddedResourcesPromise = fetchBootConfigAsync ( ) . then ( bootConfig => {
15
- return loadEmbeddedResourcesAsync ( bootConfig ) ;
16
- } ) ;
15
+ await startCicuit ( ) ;
17
16
18
- connection = new signalR . HubConnectionBuilder ( )
19
- . withUrl ( '_blazor' )
20
- . withHubProtocol ( new MessagePackHubProtocol ( ) )
21
- . configureLogging ( signalR . LogLevel . Information )
22
- . build ( ) ;
17
+ async function startCicuit ( ) : Promise < void > {
18
+ // In the background, start loading the boot config and any embedded resources
19
+ const embeddedResourcesPromise = fetchBootConfigAsync ( ) . then ( bootConfig => {
20
+ return loadEmbeddedResourcesAsync ( bootConfig ) ;
21
+ } ) ;
22
+
23
+ const initialConnection = await initializeConnection ( ) ;
24
+
25
+ // Ensure any embedded resources have been loaded before starting the app
26
+ await embeddedResourcesPromise ;
27
+ const circuitId = await initialConnection . invoke < string > (
28
+ 'StartCircuit' ,
29
+ uriHelperFunctions . getLocationHref ( ) ,
30
+ uriHelperFunctions . getBaseURI ( )
31
+ ) ;
32
+
33
+ window [ 'Blazor' ] . reconnect = async ( ) => {
34
+ const reconnection = await initializeConnection ( ) ;
35
+ if ( ! await reconnection . invoke < Boolean > ( 'ConnectCircuit' , circuitId ) ) {
36
+ throw "Failed to reconnect to the server" ;
37
+ }
38
+
39
+ circuitHandlers . forEach ( h => h . onConnectionUp ( ) ) ;
40
+ } ;
41
+
42
+ circuitHandlers . forEach ( h => h . onConnectionUp ( ) ) ;
43
+ }
44
+
45
+ async function initializeConnection ( ) : Promise < signalR . HubConnection > {
46
+ const connection = new signalR . HubConnectionBuilder ( )
47
+ . withUrl ( '_blazor' )
48
+ . withHubProtocol ( new MessagePackHubProtocol ( ) )
49
+ . configureLogging ( signalR . LogLevel . Information )
50
+ . build ( ) ;
51
+ connection . on ( 'JS.BeginInvokeJS' , DotNet . jsCallDispatcher . beginInvokeJSFromDotNet ) ;
52
+ connection . on ( 'JS.RenderBatch' , ( browserRendererId : number , renderId : number , batchData : Uint8Array ) => {
53
+ try {
54
+ renderBatch ( browserRendererId , new OutOfProcessRenderBatch ( batchData ) ) ;
55
+ connection . send ( 'OnRenderCompleted' , renderId , null ) ;
56
+ }
57
+ catch ( ex ) {
58
+ // If there's a rendering exception, notify server *and* throw on client
59
+ connection . send ( 'OnRenderCompleted' , renderId , ex . toString ( ) ) ;
60
+ throw ex ;
61
+ }
62
+ } ) ;
63
+
64
+ connection . onclose ( error => circuitHandlers . forEach ( h => h . onConnectionDown ( error ) ) ) ;
65
+ connection . on ( 'JS.Error' , unhandledError . bind ( connection ) ) ;
66
+
67
+ window [ 'Blazor' ] . closeConnection = async ( ) => {
68
+ await connection . stop ( ) ;
69
+ DotNet . attachDispatcher ( {
70
+ beginInvokeDotNetFromJS : ( ...args ) => { } } ) ;
71
+ }
23
72
24
- connection . on ( 'JS.BeginInvokeJS' , DotNet . jsCallDispatcher . beginInvokeJSFromDotNet ) ;
25
- connection . on ( 'JS.RenderBatch' , ( browserRendererId : number , renderId : number , batchData : Uint8Array ) => {
26
73
try {
27
- renderBatch ( browserRendererId , new OutOfProcessRenderBatch ( batchData ) ) ;
28
- connection . send ( 'OnRenderCompleted' , renderId , null ) ;
74
+ await connection . start ( ) ;
29
75
} catch ( ex ) {
30
- // If there's a rendering exception, notify server *and* throw on client
31
- connection . send ( 'OnRenderCompleted' , renderId , ex . toString ( ) ) ;
32
- throw ex ;
76
+ unhandledError . call ( connection , ex ) ;
33
77
}
34
- } ) ;
35
78
36
- connection . on ( 'JS.Error' , unhandledError ) ;
79
+ DotNet . attachDispatcher ( {
80
+ beginInvokeDotNetFromJS : ( callId , assemblyName , methodIdentifier , dotNetObjectId , argsJson ) => {
81
+ connection . send ( 'BeginInvokeDotNetFromJS' , callId ? callId . toString ( ) : null , assemblyName , methodIdentifier , dotNetObjectId || 0 , argsJson ) ;
82
+ }
83
+ } ) ;
37
84
38
- connection . start ( )
39
- . then ( async ( ) => {
40
- DotNet . attachDispatcher ( {
41
- beginInvokeDotNetFromJS : ( callId , assemblyName , methodIdentifier , dotNetObjectId , argsJson ) => {
42
- connection . send ( 'BeginInvokeDotNetFromJS' , callId ? callId . toString ( ) : null , assemblyName , methodIdentifier , dotNetObjectId || 0 , argsJson ) ;
43
- }
44
- } ) ;
45
-
46
- // Ensure any embedded resources have been loaded before starting the app
47
- await embeddedResourcesPromise ;
48
-
49
- connection . send (
50
- 'StartCircuit' ,
51
- uriHelperFunctions . getLocationHref ( ) ,
52
- uriHelperFunctions . getBaseURI ( )
53
- ) ;
54
- } )
55
- . catch ( unhandledError ) ;
56
-
57
- // Temporary undocumented API to help with https://github.com/aspnet/Blazor/issues/1339
58
- // This will be replaced once we implement proper connection management (reconnects, etc.)
59
- window [ 'Blazor' ] . onServerConnectionClose = connection . onclose . bind ( connection ) ;
60
- }
85
+ return connection ;
86
+ }
61
87
62
- function unhandledError ( err ) {
63
- console . error ( err ) ;
64
-
65
- // Disconnect on errors.
66
- //
67
- // TODO: it would be nice to have some kind of experience for what happens when you're
68
- // trying to interact with an app that's disconnected.
69
- //
70
- // Trying to call methods on the connection after its been closed will throw.
71
- if ( connection ) {
72
- connection . stop ( ) ;
88
+ function unhandledError ( this : signalR . HubConnection , err ) {
89
+ console . error ( err ) ;
90
+
91
+ // Disconnect on errors.
92
+ //
93
+ // TODO: it would be nice to have some kind of experience for what happens when you're
94
+ // trying to interact with an app that's disconnected.
95
+ //
96
+ // Trying to call methods on the connection after its been closed will throw.
97
+ if ( this ) {
98
+ this . stop ( ) ;
99
+ }
73
100
}
74
101
}
75
102
0 commit comments