1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System . Diagnostics ;
4
5
using Aspire . Hosting . ApplicationModel ;
5
6
using Aspire . Hosting . Dashboard ;
6
7
using Aspire . Hosting . Utils ;
@@ -324,30 +325,40 @@ private static IResourceBuilder<ProjectResource> WithProjectDefaults(this IResou
324
325
}
325
326
else
326
327
{
328
+ // Set HTTP_PORTS/HTTPS_PORTS in publish mode, to override the default port set in the base image. Note that:
329
+ // - We don't set them if we have Kestrel endpoints configured, as Kestrel will get everything from its config.
330
+ // - We only do that for endpoint set explicitly (.WithHttpEndpoint), not for the ones coming from launch profile.
331
+ // This is because launch profile endpoints are not meant to be used in production.
332
+ if ( ! kestrelEndpointsByScheme . Any ( ) )
333
+ {
334
+ builder . SetBothPortsEnvVariables ( ) ;
335
+ }
336
+
327
337
// If we aren't a web project (looking at both launch profile and Kestrel config) we don't automatically add bindings.
328
338
if ( launchProfile ? . ApplicationUrl == null && ! kestrelEndpointsByScheme . Any ( ) )
329
339
{
330
340
return builder ;
331
341
}
332
342
333
- if ( ! projectResource . Annotations . OfType < EndpointAnnotation > ( ) . Any ( sb => sb . UriScheme == "http" || string . Equals ( sb . Name , "http" , StringComparisons . EndpointAnnotationName ) ) )
343
+ string [ ] schemes = [ "http" , "https" ] ;
344
+ foreach ( var scheme in schemes )
334
345
{
335
- builder . WithEndpoint ( "http" , e =>
346
+ if ( ! projectResource . Annotations . OfType < EndpointAnnotation > ( ) . Any ( sb => sb . UriScheme == scheme || string . Equals ( sb . Name , scheme , StringComparisons . EndpointAnnotationName ) ) )
336
347
{
337
- e . UriScheme = "http" ;
338
- e . Transport = adjustTransport ( e ) ;
339
- } ,
340
- createIfNotExists : true ) ;
341
- }
348
+ builder . WithEndpoint ( scheme , e =>
349
+ {
350
+ e . UriScheme = scheme ;
351
+ e . Transport = adjustTransport ( e ) ;
342
352
343
- if ( ! projectResource . Annotations . OfType < EndpointAnnotation > ( ) . Any ( sb => sb . UriScheme == "https" || string . Equals ( sb . Name , "https" , StringComparisons . EndpointAnnotationName ) ) )
344
- {
345
- builder . WithEndpoint ( "https" , e =>
346
- {
347
- e . UriScheme = "https" ;
348
- e . Transport = adjustTransport ( e ) ;
349
- } ,
350
- createIfNotExists : true ) ;
353
+ // In the https case, we don't want this default endpoint to end up in the HTTPS_PORTS env var,
354
+ // because the container likely won't be set up to listen on https (e.g. ACA case)
355
+ if ( scheme == "https" )
356
+ {
357
+ e . ExcludeFromPortEnvironment = true ;
358
+ }
359
+ } ,
360
+ createIfNotExists : true ) ;
361
+ }
351
362
}
352
363
}
353
364
@@ -440,13 +451,11 @@ private static IConfiguration GetConfiguration(ProjectResource projectResource)
440
451
return configBuilder . Build ( ) ;
441
452
}
442
453
454
+ static bool IsValidAspNetCoreUrl ( EndpointAnnotation e ) =>
455
+ e . UriScheme is "http" or "https" && e . TargetPortEnvironmentVariable is null ;
456
+
443
457
private static void SetAspNetCoreUrls ( this IResourceBuilder < ProjectResource > builder )
444
458
{
445
- if ( builder . ApplicationBuilder . ExecutionContext . IsPublishMode )
446
- {
447
- return ;
448
- }
449
-
450
459
builder . WithEnvironment ( context =>
451
460
{
452
461
if ( context . EnvironmentVariables . ContainsKey ( "ASPNETCORE_URLS" ) )
@@ -460,9 +469,6 @@ private static void SetAspNetCoreUrls(this IResourceBuilder<ProjectResource> bui
460
469
var processedHttpsPort = false ;
461
470
var first = true ;
462
471
463
- static bool IsValidAspNetCoreUrl ( EndpointAnnotation e ) =>
464
- e . UriScheme is "http" or "https" && e . TargetPortEnvironmentVariable is null ;
465
-
466
472
// Turn http and https endpoints into a single ASPNETCORE_URLS environment variable.
467
473
foreach ( var e in builder . Resource . GetEndpoints ( ) . Where ( e => IsValidAspNetCoreUrl ( e . EndpointAnnotation ) ) )
468
474
{
@@ -491,4 +497,47 @@ static bool IsValidAspNetCoreUrl(EndpointAnnotation e) =>
491
497
}
492
498
} ) ;
493
499
}
500
+
501
+ private static void SetBothPortsEnvVariables ( this IResourceBuilder < ProjectResource > builder )
502
+ {
503
+ builder . WithEnvironment ( context =>
504
+ {
505
+ builder . SetOnePortsEnvVariable ( context , "HTTP_PORTS" , "http" ) ;
506
+ builder . SetOnePortsEnvVariable ( context , "HTTPS_PORTS" , "https" ) ;
507
+ } ) ;
508
+ }
509
+
510
+ private static void SetOnePortsEnvVariable ( this IResourceBuilder < ProjectResource > builder , EnvironmentCallbackContext context , string portEnvVariable , string scheme )
511
+ {
512
+ if ( context . EnvironmentVariables . ContainsKey ( portEnvVariable ) )
513
+ {
514
+ // If the user has already set that variable, we don't want to override it.
515
+ return ;
516
+ }
517
+
518
+ var ports = new ReferenceExpressionBuilder ( ) ;
519
+ var firstPort = true ;
520
+
521
+ // Turn endpoint ports into a single environment variable
522
+ foreach ( var e in builder . Resource . GetEndpoints ( ) . Where ( e => IsValidAspNetCoreUrl ( e . EndpointAnnotation ) ) )
523
+ {
524
+ if ( e . EndpointAnnotation . UriScheme == scheme && ! e . EndpointAnnotation . ExcludeFromPortEnvironment )
525
+ {
526
+ Debug . Assert ( ! e . EndpointAnnotation . FromLaunchProfile , "Endpoints from launch profile should never make it here" ) ;
527
+
528
+ if ( ! firstPort )
529
+ {
530
+ ports . AppendLiteral ( ";" ) ;
531
+ }
532
+
533
+ ports . Append ( $ "{ e . Property ( EndpointProperty . TargetPort ) } ") ;
534
+ firstPort = false ;
535
+ }
536
+ }
537
+
538
+ if ( ! firstPort )
539
+ {
540
+ context . EnvironmentVariables [ portEnvVariable ] = ports . Build ( ) ;
541
+ }
542
+ }
494
543
}
0 commit comments