44using System ;
55using System . Collections . Generic ;
66using System . ComponentModel . Design ;
7+ using System . Linq ;
78using System . Security . Cryptography . X509Certificates ;
89using System . Threading . Tasks ;
10+ using Autofac ;
11+ using Autofac . Core ;
12+ using Autofac . Extensions . DependencyInjection ;
913using Microsoft . Extensions . DependencyInjection ;
1014using Microsoft . WindowsAzure . Storage ;
15+ using Microsoft . WindowsAzure . Storage . Blob ;
1116using Newtonsoft . Json . Linq ;
1217using NuGet . Jobs ;
1318using NuGet . Services . Incidents ;
19+ using NuGet . Services . Status . Table . Manual ;
20+ using StatusAggregator . Manual ;
1421using StatusAggregator . Parse ;
1522using StatusAggregator . Table ;
1623
@@ -26,10 +33,14 @@ public override void Init(IServiceContainer serviceContainer, IDictionary<string
2633
2734 AddLogging ( serviceCollection ) ;
2835 AddConfiguration ( serviceCollection , jobArgsDictionary ) ;
29- AddStorage ( serviceCollection ) ;
3036 AddServices ( serviceCollection ) ;
3137
32- _serviceProvider = serviceCollection . BuildServiceProvider ( ) ;
38+ var containerBuilder = new ContainerBuilder ( ) ;
39+ containerBuilder . Populate ( serviceCollection ) ;
40+
41+ AddStorage ( containerBuilder ) ;
42+
43+ _serviceProvider = new AutofacServiceProvider ( containerBuilder . Build ( ) ) ;
3344 }
3445
3546 public override Task Run ( )
@@ -48,11 +59,23 @@ private static void AddServices(IServiceCollection serviceCollection)
4859 serviceCollection . AddTransient < IIncidentFactory , IncidentFactory > ( ) ;
4960 AddParsing ( serviceCollection ) ;
5061 serviceCollection . AddTransient < IIncidentUpdater , IncidentUpdater > ( ) ;
62+ AddManualStatusChangeHandling ( serviceCollection ) ;
5163 serviceCollection . AddTransient < IStatusUpdater , StatusUpdater > ( ) ;
5264 serviceCollection . AddTransient < IStatusExporter , StatusExporter > ( ) ;
5365 serviceCollection . AddTransient < StatusAggregator > ( ) ;
5466 }
5567
68+ private static void AddManualStatusChangeHandling ( IServiceCollection serviceCollection )
69+ {
70+ serviceCollection . AddTransient < IManualStatusChangeHandler < AddStatusEventManualChangeEntity > , AddStatusEventManualChangeHandler > ( ) ;
71+ serviceCollection . AddTransient < IManualStatusChangeHandler < EditStatusEventManualChangeEntity > , EditStatusEventManualChangeHandler > ( ) ;
72+ serviceCollection . AddTransient < IManualStatusChangeHandler < DeleteStatusEventManualChangeEntity > , DeleteStatusEventManualChangeHandler > ( ) ;
73+ serviceCollection . AddTransient < IManualStatusChangeHandler < AddStatusMessageManualChangeEntity > , AddStatusMessageManualChangeHandler > ( ) ;
74+ serviceCollection . AddTransient < IManualStatusChangeHandler < EditStatusMessageManualChangeEntity > , EditStatusMessageManualChangeHandler > ( ) ;
75+ serviceCollection . AddTransient < IManualStatusChangeHandler < DeleteStatusMessageManualChangeEntity > , DeleteStatusMessageManualChangeHandler > ( ) ;
76+ serviceCollection . AddTransient < IManualStatusChangeHandler , ManualStatusChangeHandler > ( ) ;
77+ }
78+
5679 private static void AddParsing ( IServiceCollection serviceCollection )
5780 {
5881 serviceCollection . AddTransient < IIncidentParsingFilter , SeverityFilter > ( ) ;
@@ -66,31 +89,78 @@ private static void AddParsing(IServiceCollection serviceCollection)
6689 serviceCollection . AddTransient < IAggregateIncidentParser , AggregateIncidentParser > ( ) ;
6790 }
6891
69- private static void AddStorage ( IServiceCollection serviceCollection )
92+ private const string StorageAccountNameParameter = "name" ;
93+
94+ private const string PrimaryStorageAccountName = "Primary" ;
95+ private const string SecondaryStorageAccountName = "Secondary" ;
96+
97+ private static void AddStorage ( ContainerBuilder containerBuilder )
98+ {
99+ var statusStorageConnectionBuilders = new StatusStorageConnectionBuilder [ ]
100+ {
101+ new StatusStorageConnectionBuilder ( PrimaryStorageAccountName , configuration => configuration . StorageAccount ) ,
102+ new StatusStorageConnectionBuilder ( SecondaryStorageAccountName , configuration => configuration . StorageAccountSecondary )
103+ } ;
104+
105+ // Add all storages to the container by name.
106+ foreach ( var statusStorageConnectionBuilder in
107+ // Register the primary storage last, so it will be the default and will be used unless a specific storage is referenced.
108+ statusStorageConnectionBuilders . OrderBy ( b => b . Name == PrimaryStorageAccountName ) )
109+ {
110+ var name = statusStorageConnectionBuilder . Name ;
111+
112+ containerBuilder
113+ . Register ( ctx => GetCloudStorageAccount ( ctx , statusStorageConnectionBuilder ) )
114+ . As < CloudStorageAccount > ( )
115+ . Named < CloudStorageAccount > ( name ) ;
116+
117+ containerBuilder
118+ . Register ( ctx =>
119+ {
120+ var storageAccount = ctx . ResolveNamed < CloudStorageAccount > ( name ) ;
121+ return GetTableWrapper ( ctx , storageAccount ) ;
122+ } )
123+ . As < ITableWrapper > ( )
124+ . Named < ITableWrapper > ( name ) ;
125+
126+ containerBuilder
127+ . Register ( ctx =>
128+ {
129+ var storageAccount = ctx . ResolveNamed < CloudStorageAccount > ( name ) ;
130+ return GetCloudBlobContainer ( ctx , storageAccount ) ;
131+ } )
132+ . As < CloudBlobContainer > ( )
133+ . Named < CloudBlobContainer > ( name ) ;
134+
135+ // We need to listen to manual status change updates from each storage.
136+ containerBuilder
137+ . RegisterType < ManualStatusChangeUpdater > ( )
138+ . WithParameter ( new NamedParameter ( StorageAccountNameParameter , name ) )
139+ . WithParameter ( new ResolvedParameter (
140+ ( pi , ctx ) => pi . ParameterType == typeof ( ITableWrapper ) ,
141+ ( pi , ctx ) => ctx . ResolveNamed < ITableWrapper > ( name ) ) )
142+ . As < IManualStatusChangeUpdater > ( )
143+ . Named < IManualStatusChangeUpdater > ( name ) ;
144+ }
145+ }
146+
147+ private static CloudStorageAccount GetCloudStorageAccount ( IComponentContext ctx , StatusStorageConnectionBuilder statusStorageConnectionBuilder )
148+ {
149+ var configuration = ctx . Resolve < StatusAggregatorConfiguration > ( ) ;
150+ return CloudStorageAccount . Parse ( statusStorageConnectionBuilder . GetConnectionString ( configuration ) ) ;
151+ }
152+
153+ private static ITableWrapper GetTableWrapper ( IComponentContext ctx , CloudStorageAccount storageAccount )
154+ {
155+ var configuration = ctx . Resolve < StatusAggregatorConfiguration > ( ) ;
156+ return new TableWrapper ( storageAccount , configuration . TableName ) ;
157+ }
158+
159+ private static CloudBlobContainer GetCloudBlobContainer ( IComponentContext ctx , CloudStorageAccount storageAccount )
70160 {
71- serviceCollection . AddSingleton (
72- serviceProvider =>
73- {
74- var configuration = serviceProvider . GetRequiredService < StatusAggregatorConfiguration > ( ) ;
75- return CloudStorageAccount . Parse ( configuration . StorageAccount ) ;
76- } ) ;
77-
78- serviceCollection . AddSingleton < ITableWrapper > (
79- serviceProvider =>
80- {
81- var storageAccount = serviceProvider . GetRequiredService < CloudStorageAccount > ( ) ;
82- var configuration = serviceProvider . GetRequiredService < StatusAggregatorConfiguration > ( ) ;
83- return new TableWrapper ( storageAccount , configuration . TableName ) ;
84- } ) ;
85-
86- serviceCollection . AddSingleton (
87- serviceProvider =>
88- {
89- var storageAccount = serviceProvider . GetRequiredService < CloudStorageAccount > ( ) ;
90- var blobClient = storageAccount . CreateCloudBlobClient ( ) ;
91- var configuration = serviceProvider . GetRequiredService < StatusAggregatorConfiguration > ( ) ;
92- return blobClient . GetContainerReference ( configuration . ContainerName ) ;
93- } ) ;
161+ var blobClient = storageAccount . CreateCloudBlobClient ( ) ;
162+ var configuration = ctx . Resolve < StatusAggregatorConfiguration > ( ) ;
163+ return blobClient . GetContainerReference ( configuration . ContainerName ) ;
94164 }
95165
96166 private const int _defaultEventStartMessageDelayMinutes = 15 ;
@@ -101,8 +171,10 @@ private static void AddConfiguration(IServiceCollection serviceCollection, IDict
101171 {
102172 var configuration = new StatusAggregatorConfiguration ( )
103173 {
104- StorageAccount =
174+ StorageAccount =
105175 JobConfigurationManager . GetArgument ( jobArgsDictionary , JobArgumentNames . StatusStorageAccount ) ,
176+ StorageAccountSecondary =
177+ JobConfigurationManager . GetArgument ( jobArgsDictionary , JobArgumentNames . StatusStorageAccountSecondary ) ,
106178 ContainerName =
107179 JobConfigurationManager . GetArgument ( jobArgsDictionary , JobArgumentNames . StatusContainerName ) ,
108180 TableName =
0 commit comments