88using System . IO ;
99using System . Linq ;
1010using System . Net ;
11+ using System . Net . Http ;
1112using System . Net . Mail ;
1213using System . Security . Principal ;
1314using System . Threading . Tasks ;
1617using System . Web . Mvc ;
1718using AnglicanGeek . MarkdownMailer ;
1819using Autofac ;
20+ using Autofac . Extensions . DependencyInjection ;
1921using Autofac . Core ;
2022using Elmah ;
23+ using Microsoft . ApplicationInsights . Extensibility ;
24+ using Microsoft . Extensions . DependencyInjection ;
2125using Microsoft . Extensions . Logging ;
2226using Microsoft . WindowsAzure . ServiceRuntime ;
2327using NuGet . Services . Entities ;
2832using NuGet . Services . Messaging ;
2933using NuGet . Services . Messaging . Email ;
3034using NuGet . Services . Search . Client ;
35+ using NuGet . Services . Search . Client . Correlation ;
3136using NuGet . Services . ServiceBus ;
3237using NuGet . Services . Sql ;
3338using NuGet . Services . Validation ;
4247using NuGetGallery . Features ;
4348using NuGetGallery . Infrastructure ;
4449using NuGetGallery . Infrastructure . Authentication ;
45- using NuGetGallery . Infrastructure . Lucene ;
4650using NuGetGallery . Infrastructure . Mail ;
51+ using NuGetGallery . Infrastructure . Search ;
4752using NuGetGallery . Security ;
4853using SecretReaderFactory = NuGetGallery . Configuration . SecretReader . SecretReaderFactory ;
4954
@@ -62,15 +67,30 @@ public static class BindingKeys
6267
6368 protected override void Load ( ContainerBuilder builder )
6469 {
65- var loggerConfiguration = LoggingSetup . CreateDefaultLoggerConfiguration ( withConsoleLogger : false ) ;
66- var loggerFactory = LoggingSetup . CreateLoggerFactory ( loggerConfiguration ) ;
67- builder . RegisterInstance ( loggerFactory )
70+ var services = new ServiceCollection ( ) ;
71+
72+ var configuration = new ConfigurationService ( ) ;
73+ var secretReaderFactory = new SecretReaderFactory ( configuration ) ;
74+ var secretReader = secretReaderFactory . CreateSecretReader ( ) ;
75+ var secretInjector = secretReaderFactory . CreateSecretInjector ( secretReader ) ;
76+
77+ builder . RegisterInstance ( secretInjector )
6878 . AsSelf ( )
69- . As < ILoggerFactory > ( ) ;
70- builder . RegisterGeneric ( typeof ( Logger < > ) )
71- . As ( typeof ( ILogger < > ) )
79+ . As < ISecretInjector > ( )
7280 . SingleInstance ( ) ;
7381
82+ configuration . SecretInjector = secretInjector ;
83+
84+ // Register the ILoggerFactory and configure it to use AppInsights if an instrumentation key is provided.
85+ var instrumentationKey = configuration . Current . AppInsightsInstrumentationKey ;
86+ if ( ! string . IsNullOrEmpty ( instrumentationKey ) )
87+ {
88+ TelemetryConfiguration . Active . InstrumentationKey = instrumentationKey ;
89+ }
90+
91+ var loggerConfiguration = LoggingSetup . CreateDefaultLoggerConfiguration ( withConsoleLogger : false ) ;
92+ var loggerFactory = LoggingSetup . CreateLoggerFactory ( loggerConfiguration ) ;
93+
7494 var telemetryClient = TelemetryClientWrapper . Instance ;
7595 builder . RegisterInstance ( telemetryClient )
7696 . AsSelf ( )
@@ -83,17 +103,8 @@ protected override void Load(ContainerBuilder builder)
83103 . As < IDiagnosticsService > ( )
84104 . SingleInstance ( ) ;
85105
86- var configuration = new ConfigurationService ( ) ;
87- var secretReaderFactory = new SecretReaderFactory ( configuration ) ;
88- var secretReader = secretReaderFactory . CreateSecretReader ( ) ;
89- var secretInjector = secretReaderFactory . CreateSecretInjector ( secretReader ) ;
90-
91- builder . RegisterInstance ( secretInjector )
92- . AsSelf ( )
93- . As < ISecretInjector > ( )
94- . SingleInstance ( ) ;
95-
96- configuration . SecretInjector = secretInjector ;
106+ services . AddSingleton ( loggerFactory ) ;
107+ services . AddSingleton ( typeof ( ILogger < > ) , typeof ( Logger < > ) ) ;
97108
98109 UrlHelperExtensions . SetConfigurationService ( configuration ) ;
99110
@@ -113,7 +124,9 @@ protected override void Load(ContainerBuilder builder)
113124 builder . Register ( c => configuration . PackageDelete )
114125 . As < IPackageDeleteConfiguration > ( ) ;
115126
116- builder . RegisterType < TelemetryService > ( )
127+ var telemetryService = new TelemetryService ( diagnosticsService , telemetryClient ) ;
128+ builder . RegisterInstance ( telemetryService )
129+ . AsSelf ( )
117130 . As < ITelemetryService > ( )
118131 . As < IFeatureFlagTelemetryService > ( )
119132 . SingleInstance ( ) ;
@@ -125,6 +138,7 @@ protected override void Load(ContainerBuilder builder)
125138 . As < Lucene . Net . Store . Directory > ( )
126139 . SingleInstance ( ) ;
127140
141+ ConfigureResilientSearch ( loggerFactory , configuration , telemetryService , services ) ;
128142 ConfigureSearch ( builder , configuration ) ;
129143
130144 builder . RegisterType < DateTimeProvider > ( ) . AsSelf ( ) . As < IDateTimeProvider > ( ) . SingleInstance ( ) ;
@@ -422,6 +436,7 @@ protected override void Load(ContainerBuilder builder)
422436 }
423437
424438 ConfigureAutocomplete ( builder , configuration ) ;
439+ builder . Populate ( services ) ;
425440 }
426441
427442 private static void RegisterFeatureFlagsService ( ContainerBuilder builder , ConfigurationService configuration )
@@ -694,6 +709,55 @@ private static void ConfigureSearch(ContainerBuilder builder, IGalleryConfigurat
694709 }
695710 }
696711
712+ private static List < ( string name , Uri searchUri ) > GetSearchClientsFromConfiguration ( IGalleryConfigurationService configuration )
713+ {
714+ List < ( string name , Uri searchUri ) > searchClients = new List < ( string name , Uri searchUri ) > ( ) ;
715+ if ( configuration . Current . SearchServiceUriPrimary != null )
716+ {
717+ searchClients . Add ( ( SearchClientConfiguration . SearchPrimaryInstance , configuration . Current . SearchServiceUriPrimary ) ) ;
718+ }
719+ if ( configuration . Current . SearchServiceUriSecondary != null )
720+ {
721+ searchClients . Add ( ( SearchClientConfiguration . SearchSecondaryInstance , configuration . Current . SearchServiceUriSecondary ) ) ;
722+ }
723+
724+ return searchClients ;
725+ }
726+
727+ private static void ConfigureResilientSearch ( ILoggerFactory loggerFactory , IGalleryConfigurationService configuration , ITelemetryService telemetryService , ServiceCollection services )
728+ {
729+ var searchClients = GetSearchClientsFromConfiguration ( configuration ) ;
730+
731+ if ( searchClients . Count >= 1 )
732+ {
733+ var logger = loggerFactory . CreateLogger < SearchClientPolicies > ( ) ;
734+ services . AddTransient < CorrelatingHttpClientHandler > ( ) ;
735+ services . AddTransient ( ( s ) => new TracingHttpHandler ( DependencyResolver . Current . GetService < IDiagnosticsService > ( ) . SafeGetSource ( "ExternalSearchService" ) ) ) ;
736+
737+ foreach ( var searchClient in searchClients )
738+ {
739+ // The policy handlers will be applied from the bottom to the top.
740+ // The most inner one is the one added last.
741+ services . AddHttpClient < IHttpClientWrapper , HttpClientWrapper > ( searchClient . name , c =>
742+ c . BaseAddress = searchClient . searchUri )
743+ . ConfigurePrimaryHttpMessageHandler ( ( ) => new HttpClientHandler ( ) { AllowAutoRedirect = true } )
744+ . AddHttpMessageHandler < TracingHttpHandler > ( )
745+ . AddHttpMessageHandler < CorrelatingHttpClientHandler > ( )
746+ . AddPolicyHandler ( SearchClientPolicies . SearchClientFallBackCircuitBreakerPolicy ( logger , searchClient . name , telemetryService ) )
747+ . AddPolicyHandler ( SearchClientPolicies . SearchClientWaitAndRetryForeverPolicy ( logger , searchClient . name , telemetryService ) )
748+ . AddPolicyHandler ( SearchClientPolicies . SearchClientCircuitBreakerPolicy (
749+ SearchClientConfiguration . SearchRetryCount ,
750+ TimeSpan . FromSeconds ( configuration . Current . SearchCircuitBreakerDelayInSeconds ) ,
751+ logger ,
752+ searchClient . name ,
753+ telemetryService ) ) ;
754+ }
755+ services . AddTransient < IResilientSearchClient , ResilientSearchHttpClient > ( ) ;
756+ services . AddTransient < ISearchClient , GallerySearchClient > ( ) ;
757+ }
758+ }
759+
760+
697761 private static void ConfigureAutocomplete ( ContainerBuilder builder , IGalleryConfigurationService configuration )
698762 {
699763 if ( configuration . Current . ServiceDiscoveryUri != null &&
0 commit comments