@@ -14,10 +14,14 @@ internal sealed partial class BrowserConnector(DotNetWatchContext context) : IAs
14
14
// This needs to be in sync with the version BrowserRefreshMiddleware is compiled against.
15
15
private static readonly Version s_minimumSupportedVersion = Versions . Version6_0 ;
16
16
17
- private static readonly Regex s_nowListeningRegex = s_nowListeningOnRegex ( ) ;
17
+ private static readonly Regex s_nowListeningRegex = GetNowListeningOnRegex ( ) ;
18
+ private static readonly Regex s_aspireDashboardUrlRegex = GetAspireDashboardUrlRegex ( ) ;
18
19
19
20
[ GeneratedRegex ( @"Now listening on: (?<url>.*)\s*$" , RegexOptions . Compiled ) ]
20
- private static partial Regex s_nowListeningOnRegex ( ) ;
21
+ private static partial Regex GetNowListeningOnRegex ( ) ;
22
+
23
+ [ GeneratedRegex ( @"Login to the dashboard at (?<url>.*)\s*$" , RegexOptions . Compiled ) ]
24
+ private static partial Regex GetAspireDashboardUrlRegex ( ) ;
21
25
22
26
private readonly object _serversGuard = new ( ) ;
23
27
private readonly Dictionary < ProjectGraphNode , BrowserRefreshServer ? > _servers = [ ] ;
@@ -117,6 +121,10 @@ public bool TryGetRefreshServer(ProjectGraphNode projectNode, [NotNullWhen(true)
117
121
118
122
bool matchFound = false ;
119
123
124
+ // Workaround for Aspire dashboard launching: scan for "Login to the dashboard at " prefix in the output and use the URL.
125
+ // TODO: Share launch profile processing logic as implemented in VS with dotnet-run and implement browser launching there.
126
+ var isAspireHost = projectNode . GetCapabilities ( ) . Contains ( AspireServiceFactory . AppHostProjectCapability ) ;
127
+
120
128
return handler ;
121
129
122
130
void handler ( OutputLine line )
@@ -129,7 +137,7 @@ void handler(OutputLine line)
129
137
return ;
130
138
}
131
139
132
- var match = s_nowListeningRegex . Match ( line . Content ) ;
140
+ var match = ( isAspireHost ? s_aspireDashboardUrlRegex : s_nowListeningRegex ) . Match ( line . Content ) ;
133
141
if ( ! match . Success )
134
142
{
135
143
return ;
@@ -141,7 +149,8 @@ void handler(OutputLine line)
141
149
if ( projectAddedToAttemptedSet )
142
150
{
143
151
// first iteration:
144
- LaunchBrowser ( launchProfile , match . Groups [ "url" ] . Value , server ) ;
152
+ var launchUrl = GetLaunchUrl ( launchProfile . LaunchUrl , match . Groups [ "url" ] . Value ) ;
153
+ LaunchBrowser ( launchUrl , server ) ;
145
154
}
146
155
else if ( server != null )
147
156
{
@@ -153,10 +162,15 @@ void handler(OutputLine line)
153
162
}
154
163
}
155
164
156
- private void LaunchBrowser ( LaunchSettingsProfile launchProfile , string launchUrl , BrowserRefreshServer ? server )
165
+ public static string GetLaunchUrl ( string ? profileLaunchUrl , string outputLaunchUrl )
166
+ => string . IsNullOrWhiteSpace ( profileLaunchUrl ) ? outputLaunchUrl :
167
+ Uri . TryCreate ( profileLaunchUrl , UriKind . Absolute , out _ ) ? profileLaunchUrl :
168
+ Uri . TryCreate ( outputLaunchUrl , UriKind . Absolute , out var launchUri ) ? new Uri ( launchUri , profileLaunchUrl ) . ToString ( ) :
169
+ outputLaunchUrl ;
170
+
171
+ private void LaunchBrowser ( string launchUrl , BrowserRefreshServer ? server )
157
172
{
158
- var launchPath = launchProfile . LaunchUrl ;
159
- var fileName = Uri . TryCreate ( launchPath , UriKind . Absolute , out _ ) ? launchPath : launchUrl + "/" + launchPath ;
173
+ var fileName = launchUrl ;
160
174
161
175
var args = string . Empty ;
162
176
if ( EnvironmentVariables . BrowserPath is { } browserPath )
0 commit comments