1
- var configuration = GetConfiguration ( ) ;
1
+ var builder = WebApplication . CreateBuilder ( args ) ;
2
+ builder . Services . AddControllersWithViews ( ) ;
2
3
3
- Log . Logger = CreateSerilogLogger ( configuration ) ;
4
+ AddApplicationInsights ( builder ) ;
5
+ AddHealthChecks ( builder ) ;
6
+ AddCustomMvc ( builder ) ;
7
+ AddHttpClientServices ( builder ) ;
8
+ AddCustomAuthentication ( builder ) ;
4
9
5
- try
6
- {
7
- Log . Information ( "Configuring web host ({ApplicationContext})..." , Program . AppName ) ;
8
- var host = BuildWebHost ( configuration , args ) ;
10
+ builder . WebHost . CaptureStartupErrors ( false ) ;
11
+ builder . Host . UseSerilog ( CreateSerilogLogger ( builder . Configuration ) ) ;
9
12
10
- Log . Information ( "Starting web host ({ApplicationContext})..." , Program . AppName ) ;
11
- host . Run ( ) ;
13
+ var app = builder . Build ( ) ;
12
14
13
- return 0 ;
15
+ JwtSecurityTokenHandler . DefaultInboundClaimTypeMap . Remove ( "sub" ) ;
16
+ if ( app . Environment . IsDevelopment ( ) )
17
+ {
18
+ app . UseDeveloperExceptionPage ( ) ;
14
19
}
15
- catch ( Exception ex )
20
+ else
16
21
{
17
- Log . Fatal ( ex , "Program terminated unexpectedly ({ApplicationContext})!" , Program . AppName ) ;
18
- return 1 ;
22
+ app . UseExceptionHandler ( "/Error" ) ;
19
23
}
20
- finally
24
+
25
+ var pathBase = builder . Configuration [ "PATH_BASE" ] ;
26
+
27
+ if ( ! string . IsNullOrEmpty ( pathBase ) )
21
28
{
22
- Log . CloseAndFlush ( ) ;
29
+ app . UsePathBase ( pathBase ) ;
23
30
}
24
31
25
- IWebHost BuildWebHost ( IConfiguration configuration , string [ ] args ) =>
26
- WebHost . CreateDefaultBuilder ( args )
27
- . CaptureStartupErrors ( false )
28
- . ConfigureAppConfiguration ( x => x . AddConfiguration ( configuration ) )
29
- . UseStartup < Startup > ( )
30
- . UseSerilog ( )
31
- . Build ( ) ;
32
+ app . UseStaticFiles ( ) ;
33
+ app . UseSession ( ) ;
34
+
35
+ WebContextSeed . Seed ( app , app . Environment ) ;
36
+
37
+ // Fix samesite issue when running eShop from docker-compose locally as by default http protocol is being used
38
+ // Refer to https://github.com/dotnet-architecture/eShopOnContainers/issues/1391
39
+ app . UseCookiePolicy ( new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode . Lax } ) ;
40
+
41
+ app . UseRouting ( ) ;
42
+
43
+ app . UseAuthentication ( ) ;
44
+ app . UseAuthorization ( ) ;
45
+
46
+ app . MapControllerRoute ( "default" , "{controller=Catalog}/{action=Index}/{id?}" ) ;
47
+ app . MapControllerRoute ( "defaultError" , "{controller=Error}/{action=Error}" ) ;
48
+ app . MapControllers ( ) ;
49
+ app . MapHealthChecks ( "/liveness" , new HealthCheckOptions
50
+ {
51
+ Predicate = r => r . Name . Contains ( "self" )
52
+ } ) ;
53
+ app . MapHealthChecks ( "/hc" , new HealthCheckOptions ( )
54
+ {
55
+ Predicate = _ => true ,
56
+ ResponseWriter = UIResponseWriter . WriteHealthCheckUIResponse
57
+ } ) ;
58
+
59
+ await app . RunAsync ( ) ;
32
60
33
61
Serilog . ILogger CreateSerilogLogger ( IConfiguration configuration )
34
62
{
35
63
var seqServerUrl = configuration [ "Serilog:SeqServerUrl" ] ;
36
64
var logstashUrl = configuration [ "Serilog:LogstashgUrl" ] ;
37
65
var cfg = new LoggerConfiguration ( )
38
66
. ReadFrom . Configuration ( configuration )
39
- . Enrich . WithProperty ( "ApplicationContext" , Program . AppName )
67
+ . Enrich . WithProperty ( "ApplicationContext" , AppName )
40
68
. Enrich . FromLogContext ( )
41
69
. WriteTo . Console ( ) ;
42
70
if ( ! string . IsNullOrWhiteSpace ( seqServerUrl ) )
@@ -50,19 +78,100 @@ Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
50
78
return cfg . CreateLogger ( ) ;
51
79
}
52
80
53
- IConfiguration GetConfiguration ( )
81
+ static void AddApplicationInsights ( WebApplicationBuilder builder )
82
+ {
83
+ builder . Services . AddApplicationInsightsTelemetry ( builder . Configuration ) ;
84
+ builder . Services . AddApplicationInsightsKubernetesEnricher ( ) ;
85
+ }
86
+
87
+ static void AddHealthChecks ( WebApplicationBuilder builder )
88
+ {
89
+ builder . Services . AddHealthChecks ( )
90
+ . AddCheck ( "self" , ( ) => HealthCheckResult . Healthy ( ) )
91
+ . AddUrlGroup ( new Uri ( builder . Configuration [ "IdentityUrlHC" ] ) , name : "identityapi-check" , tags : new string [ ] { "identityapi" } ) ;
92
+ }
93
+
94
+ static void AddCustomMvc ( WebApplicationBuilder builder )
54
95
{
55
- var builder = new ConfigurationBuilder ( )
56
- . SetBasePath ( Directory . GetCurrentDirectory ( ) )
57
- . AddJsonFile ( "appsettings.json" , optional : false , reloadOnChange : true )
58
- . AddEnvironmentVariables ( ) ;
96
+ builder . Services . AddOptions ( )
97
+ . Configure < AppSettings > ( builder . Configuration )
98
+ . AddSession ( )
99
+ . AddDistributedMemoryCache ( ) ;
59
100
60
- return builder . Build ( ) ;
101
+ if ( builder . Configuration . GetValue < string > ( "IsClusterEnv" ) == bool . TrueString )
102
+ {
103
+ builder . Services . AddDataProtection ( opts =>
104
+ {
105
+ opts . ApplicationDiscriminator = "eshop.webmvc" ;
106
+ } )
107
+ . PersistKeysToStackExchangeRedis ( ConnectionMultiplexer . Connect ( builder . Configuration [ "DPConnectionString" ] ) , "DataProtection-Keys" ) ;
108
+ }
109
+ }
110
+
111
+ // Adds all Http client services
112
+ static void AddHttpClientServices ( WebApplicationBuilder builder )
113
+ {
114
+ builder . Services . AddSingleton < IHttpContextAccessor , HttpContextAccessor > ( ) ;
115
+
116
+ //register delegating handlers
117
+ builder . Services . AddTransient < HttpClientAuthorizationDelegatingHandler > ( )
118
+ . AddTransient < HttpClientRequestIdDelegatingHandler > ( ) ;
119
+
120
+ //set 5 min as the lifetime for each HttpMessageHandler int the pool
121
+ builder . Services . AddHttpClient ( "extendedhandlerlifetime" ) . SetHandlerLifetime ( TimeSpan . FromMinutes ( 5 ) ) ;
122
+
123
+ //add http client services
124
+ builder . Services . AddHttpClient < IBasketService , BasketService > ( )
125
+ . SetHandlerLifetime ( TimeSpan . FromMinutes ( 5 ) ) //Sample. Default lifetime is 2 minutes
126
+ . AddHttpMessageHandler < HttpClientAuthorizationDelegatingHandler > ( ) ;
127
+
128
+ builder . Services . AddHttpClient < ICatalogService , CatalogService > ( ) ;
129
+
130
+ builder . Services . AddHttpClient < IOrderingService , OrderingService > ( )
131
+ . AddHttpMessageHandler < HttpClientAuthorizationDelegatingHandler > ( )
132
+ . AddHttpMessageHandler < HttpClientRequestIdDelegatingHandler > ( ) ;
133
+
134
+
135
+ //add custom application services
136
+ builder . Services . AddTransient < IIdentityParser < ApplicationUser > , IdentityParser > ( ) ;
61
137
}
62
138
139
+ static void AddCustomAuthentication ( WebApplicationBuilder builder )
140
+ {
141
+ var identityUrl = builder . Configuration . GetValue < string > ( "IdentityUrl" ) ;
142
+ var callBackUrl = builder . Configuration . GetValue < string > ( "CallBackUrl" ) ;
143
+ var sessionCookieLifetime = builder . Configuration . GetValue ( "SessionCookieLifetimeMinutes" , 60 ) ;
144
+
145
+ // Add Authentication services
146
+
147
+ builder . Services . AddAuthentication ( options =>
148
+ {
149
+ options . DefaultScheme = CookieAuthenticationDefaults . AuthenticationScheme ;
150
+ options . DefaultChallengeScheme = OpenIdConnectDefaults . AuthenticationScheme ;
151
+ } )
152
+ . AddCookie ( setup => setup . ExpireTimeSpan = TimeSpan . FromMinutes ( sessionCookieLifetime ) )
153
+ . AddOpenIdConnect ( OpenIdConnectDefaults . AuthenticationScheme , options =>
154
+ {
155
+ options . SignInScheme = CookieAuthenticationDefaults . AuthenticationScheme ;
156
+ options . Authority = identityUrl . ToString ( ) ;
157
+ options . SignedOutRedirectUri = callBackUrl . ToString ( ) ;
158
+ options . ClientId = "mvc" ;
159
+ options . ClientSecret = "secret" ;
160
+ options . ResponseType = "code" ;
161
+ options . SaveTokens = true ;
162
+ options . GetClaimsFromUserInfoEndpoint = true ;
163
+ options . RequireHttpsMetadata = false ;
164
+ options . Scope . Add ( "openid" ) ;
165
+ options . Scope . Add ( "profile" ) ;
166
+ options . Scope . Add ( "orders" ) ;
167
+ options . Scope . Add ( "basket" ) ;
168
+ options . Scope . Add ( "webshoppingagg" ) ;
169
+ options . Scope . Add ( "orders.signalrhub" ) ;
170
+ options . Scope . Add ( "webhooks" ) ;
171
+ } ) ;
172
+ }
63
173
64
174
public partial class Program
65
175
{
66
- private static readonly string _namespace = typeof ( Startup ) . Namespace ;
67
- public static readonly string AppName = _namespace . Substring ( _namespace . LastIndexOf ( '.' , _namespace . LastIndexOf ( '.' ) - 1 ) + 1 ) ;
176
+ public static readonly string AppName = typeof ( Program ) . Assembly . GetName ( ) . Name ;
68
177
}
0 commit comments