44using System ;
55using System . Collections ;
66using System . Collections . Generic ;
7+ using System . Diagnostics . CodeAnalysis ;
78using System . IO ;
9+ using System . Linq ;
810using System . Net . WebSockets ;
911using System . Text ;
1012using System . Threading ;
1113using System . Threading . Tasks ;
1214using System . Web ;
1315using Microsoft . AspNetCore . Hosting ;
1416using Microsoft . Extensions . Logging ;
17+ using Microsoft . WebAssembly . AppHost . DevServer ;
1518using Microsoft . WebAssembly . Diagnostics ;
1619
1720#nullable enable
@@ -44,7 +47,7 @@ public static async Task<int> InvokeAsync(CommonConfiguration commonArgs,
4447
4548 private async Task RunAsync ( ILoggerFactory loggerFactory , CancellationToken token )
4649 {
47- if ( _args . CommonConfig . Debugging )
50+ if ( _args . CommonConfig . Debugging && ! _args . CommonConfig . UseStaticWebAssets )
4851 {
4952 ProxyOptions options = _args . CommonConfig . ToProxyOptions ( ) ;
5053 _ = Task . Run ( ( ) => DebugProxyHost . RunDebugProxyAsync ( options , Array . Empty < string > ( ) , loggerFactory , token ) , token )
@@ -75,8 +78,7 @@ private async Task RunAsync(ILoggerFactory loggerFactory, CancellationToken toke
7578 ? aspnetUrls . Split ( ';' , StringSplitOptions . RemoveEmptyEntries )
7679 : new string [ ] { $ "http://127.0.0.1:{ _args . CommonConfig . HostProperties . WebServerPort } ", "https://127.0.0.1:0" } ;
7780
78- ( ServerURLs serverURLs , IWebHost host ) = await StartWebServerAsync ( _args . CommonConfig . AppPath ,
79- _args . ForwardConsoleOutput ?? false ,
81+ ( ServerURLs serverURLs , IWebHost host ) = await StartWebServerAsync ( _args ,
8082 urls ,
8183 token ) ;
8284
@@ -85,32 +87,104 @@ private async Task RunAsync(ILoggerFactory loggerFactory, CancellationToken toke
8587 foreach ( string url in fullUrls )
8688 Console . WriteLine ( $ "App url: { url } ") ;
8789
90+ if ( serverURLs . DebugPath != null )
91+ {
92+ Console . WriteLine ( $ "Debug at url: { BuildUrl ( serverURLs . Http , serverURLs . DebugPath , string . Empty ) } ") ;
93+
94+ if ( serverURLs . Https != null )
95+ Console . WriteLine ( $ "Debug at url: { BuildUrl ( serverURLs . Https , serverURLs . DebugPath , string . Empty ) } ") ;
96+ }
97+
8898 await host . WaitForShutdownAsync ( token ) ;
8999 }
90100
91- private async Task < ( ServerURLs , IWebHost ) > StartWebServerAsync ( string appPath , bool forwardConsole , string [ ] urls , CancellationToken token )
101+ private async Task < ( ServerURLs , IWebHost ) > StartWebServerAsync ( BrowserArguments args , string [ ] urls , CancellationToken token )
92102 {
93- WasmTestMessagesProcessor ? logProcessor = null ;
94- if ( forwardConsole )
103+ Func < WebSocket , Task > ? onConsoleConnected = null ;
104+ if ( args . ForwardConsoleOutput ?? false )
95105 {
96- logProcessor = new ( _logger ) ;
106+ WasmTestMessagesProcessor logProcessor = new ( _logger ) ;
107+ onConsoleConnected = socket => RunConsoleMessagesPump ( socket , logProcessor ! , token ) ;
97108 }
98109
99- WebServerOptions options = new
100- (
101- OnConsoleConnected : forwardConsole
102- ? socket => RunConsoleMessagesPump ( socket , logProcessor ! , token )
103- : null ,
104- ContentRootPath : Path . GetFullPath ( appPath ) ,
105- WebServerUseCors : true ,
106- WebServerUseCrossOriginPolicy : true ,
107- Urls : urls
108- ) ;
109-
110- ( ServerURLs serverURLs , IWebHost host ) = await WebServer . StartAsync ( options , _logger , token ) ;
111- return ( serverURLs , host ) ;
110+ // If we are using new browser template, use dev server
111+ if ( args . CommonConfig . UseStaticWebAssets )
112+ {
113+ DevServerOptions devServerOptions = CreateDevServerOptions ( args , urls , onConsoleConnected ) ;
114+ return await DevServer . DevServer . StartAsync ( devServerOptions , _logger , token ) ;
115+ }
116+
117+ // Otherwise for old template, use web server
118+ WebServerOptions webServerOptions = CreateWebServerOptions ( urls , args . CommonConfig . AppPath , onConsoleConnected ) ;
119+ return await WebServer . StartAsync ( webServerOptions , _logger , token ) ;
112120 }
113121
122+ private static WebServerOptions CreateWebServerOptions ( string [ ] urls , string appPath , Func < WebSocket , Task > ? onConsoleConnected ) => new
123+ (
124+ OnConsoleConnected : onConsoleConnected ,
125+ ContentRootPath : Path . GetFullPath ( appPath ) ,
126+ WebServerUseCors : true ,
127+ WebServerUseCrossOriginPolicy : true ,
128+ Urls : urls
129+ ) ;
130+
131+ private static DevServerOptions CreateDevServerOptions ( BrowserArguments args , string [ ] urls , Func < WebSocket , Task > ? onConsoleConnected )
132+ {
133+ const string staticWebAssetsV1Extension = ".StaticWebAssets.xml" ;
134+ const string staticWebAssetsV2Extension = ".staticwebassets.runtime.json" ;
135+
136+ DevServerOptions ? devServerOptions = null ;
137+
138+ string appPath = args . CommonConfig . AppPath ;
139+ if ( args . CommonConfig . HostProperties . MainAssembly != null )
140+ {
141+ // If we have main assembly name, try to find static web assets manifest by precise name.
142+
143+ var mainAssemblyPath = Path . Combine ( appPath , args . CommonConfig . HostProperties . MainAssembly ) ;
144+ var staticWebAssetsPath = Path . ChangeExtension ( mainAssemblyPath , staticWebAssetsV2Extension ) ;
145+ if ( File . Exists ( staticWebAssetsPath ) )
146+ {
147+ devServerOptions = CreateDevServerOptions ( urls , staticWebAssetsPath , onConsoleConnected ) ;
148+ }
149+ else
150+ {
151+ staticWebAssetsPath = Path . ChangeExtension ( mainAssemblyPath , staticWebAssetsV1Extension ) ;
152+ if ( File . Exists ( staticWebAssetsPath ) )
153+ devServerOptions = CreateDevServerOptions ( urls , staticWebAssetsPath , onConsoleConnected ) ;
154+ }
155+
156+ if ( devServerOptions == null )
157+ devServerOptions = CreateDevServerOptions ( urls , mainAssemblyPath , onConsoleConnected ) ;
158+ }
159+ else
160+ {
161+ // If we don't have main assembly name, try to find static web assets manifest by search in the directory.
162+
163+ var staticWebAssetsPath = FindFirstFileWithExtension ( appPath , staticWebAssetsV2Extension )
164+ ?? FindFirstFileWithExtension ( appPath , staticWebAssetsV1Extension ) ;
165+
166+ if ( staticWebAssetsPath != null )
167+ devServerOptions = CreateDevServerOptions ( urls , staticWebAssetsPath , onConsoleConnected ) ;
168+
169+ if ( devServerOptions == null )
170+ throw new CommandLineException ( "Please, provide mainAssembly in hostProperties of runtimeconfig" ) ;
171+ }
172+
173+ return devServerOptions ;
174+ }
175+
176+ private static DevServerOptions CreateDevServerOptions ( string [ ] urls , string staticWebAssetsPath , Func < WebSocket , Task > ? onConsoleConnected ) => new
177+ (
178+ OnConsoleConnected : onConsoleConnected ,
179+ StaticWebAssetsPath : staticWebAssetsPath ,
180+ WebServerUseCors : true ,
181+ WebServerUseCrossOriginPolicy : true ,
182+ Urls : urls
183+ ) ;
184+
185+ private static string ? FindFirstFileWithExtension ( string directory , string extension )
186+ => Directory . EnumerateFiles ( directory , "*" + extension ) . First ( ) ;
187+
114188 private async Task RunConsoleMessagesPump ( WebSocket socket , WasmTestMessagesProcessor messagesProcessor , CancellationToken token )
115189 {
116190 byte [ ] buff = new byte [ 4000 ] ;
@@ -169,7 +243,7 @@ private string[] BuildUrls(ServerURLs serverURLs, IEnumerable<string> passThroug
169243 }
170244
171245 string query = sb . ToString ( ) ;
172- string filename = Path . GetFileName ( _args . HTMLPath ! ) ;
246+ string ? filename = _args . HTMLPath != null ? Path . GetFileName ( _args . HTMLPath ) : null ;
173247 string httpUrl = BuildUrl ( serverURLs . Http , filename , query ) ;
174248
175249 return string . IsNullOrEmpty ( serverURLs . Https )
@@ -179,12 +253,18 @@ private string[] BuildUrls(ServerURLs serverURLs, IEnumerable<string> passThroug
179253 httpUrl ,
180254 BuildUrl ( serverURLs . Https ! , filename , query )
181255 } ) ;
256+ }
182257
183- static string BuildUrl ( string baseUrl , string htmlFileName , string query )
184- => new UriBuilder ( baseUrl )
185- {
186- Query = query ,
187- Path = htmlFileName
188- } . ToString ( ) ;
258+ private static string BuildUrl ( string baseUrl , string ? htmlFileName , string query )
259+ {
260+ var uriBuilder = new UriBuilder ( baseUrl )
261+ {
262+ Query = query
263+ } ;
264+
265+ if ( htmlFileName != null )
266+ uriBuilder . Path = htmlFileName ;
267+
268+ return uriBuilder . ToString ( ) ;
189269 }
190270}
0 commit comments