1
1
using Microsoft . Extensions . Configuration ;
2
- using Serilog . Debugging ;
3
- using System ;
4
- using System . Collections . Generic ;
5
- using System . Collections . ObjectModel ;
6
- using System . Linq ;
2
+ using Serilog . Sinks . MSSqlServer . Configuration ;
7
3
8
4
namespace Serilog . Sinks . MSSqlServer
9
5
{
@@ -12,208 +8,27 @@ namespace Serilog.Sinks.MSSqlServer
12
8
/// </summary>
13
9
internal static class ApplyMicrosoftExtensionsConfiguration
14
10
{
11
+ internal static IMicrosoftExtensionsConnectionStringProvider ConnectionStringProvider { get ; set ; } = new MicrosoftExtensionsConnectionStringProvider ( ) ;
12
+
13
+ internal static IMicrosoftExtensionsColumnOptionsProvider ColumnOptionsProvider { get ; set ; } = new MicrosoftExtensionsColumnOptionsProvider ( ) ;
14
+
15
15
/// <summary>
16
16
/// Examine if supplied connection string is a reference to an item in the "ConnectionStrings" section of web.config
17
17
/// If it is, return the ConnectionStrings item, if not, return string as supplied.
18
18
/// </summary>
19
19
/// <param name="nameOrConnectionString">The name of the ConnectionStrings key or raw connection string.</param>
20
20
/// <param name="appConfiguration">Additional application-level configuration.</param>
21
21
/// <remarks>Pulled from review of Entity Framework 6 methodology for doing the same</remarks>
22
- internal static string GetConnectionString ( string nameOrConnectionString , IConfiguration appConfiguration )
23
- {
24
- // If there is an `=`, we assume this is a raw connection string not a named value
25
- // If there are no `=`, attempt to pull the named value from config
26
- if ( nameOrConnectionString . IndexOf ( '=' ) > - 1 ) return nameOrConnectionString ;
27
- string cs = appConfiguration ? . GetConnectionString ( nameOrConnectionString ) ;
28
- if ( string . IsNullOrEmpty ( cs ) )
29
- {
30
- SelfLog . WriteLine ( "MSSqlServer sink configured value {0} is not found in ConnectionStrings settings and does not appear to be a raw connection string." , nameOrConnectionString ) ;
31
- }
32
- return cs ;
33
- }
22
+ internal static string GetConnectionString ( string nameOrConnectionString , IConfiguration appConfiguration ) =>
23
+ ConnectionStringProvider . GetConnectionString ( nameOrConnectionString , appConfiguration ) ;
34
24
35
25
/// <summary>
36
26
/// Create or add to the ColumnOptions object and apply any configuration changes to it.
37
27
/// </summary>
38
28
/// <param name="columnOptions">An optional externally-created ColumnOptions object to be updated with additional configuration values.</param>
39
29
/// <param name="config">A configuration section typically named "columnOptionsSection" (see docs).</param>
40
30
/// <returns></returns>
41
- internal static ColumnOptions ConfigureColumnOptions ( ColumnOptions columnOptions , IConfigurationSection config )
42
- {
43
- // Do not use configuration binding (ie GetSection.Get<ColumnOptions>). That will create a new
44
- // ColumnOptions object which would overwrite settings if the caller passed in a ColumnOptions
45
- // object via the extension method's columnOptions parameter.
46
-
47
- var opts = columnOptions ?? new ColumnOptions ( ) ;
48
- if ( config == null || ! config . GetChildren ( ) . Any ( ) ) return opts ;
49
-
50
- AddRemoveStandardColumns ( ) ;
51
- AddAdditionalColumns ( ) ;
52
- ReadStandardColumns ( ) ;
53
- ReadMiscColumnOptions ( ) ;
54
-
55
- return opts ;
56
-
57
- void AddRemoveStandardColumns ( )
58
- {
59
- // add standard columns
60
- var addStd = config . GetSection ( "addStandardColumns" ) ;
61
- if ( addStd . GetChildren ( ) . Any ( ) )
62
- {
63
- foreach ( var col in addStd . GetChildren ( ) . ToList ( ) )
64
- {
65
- if ( Enum . TryParse ( col . Value , ignoreCase : true , result : out StandardColumn stdcol )
66
- && ! opts . Store . Contains ( stdcol ) )
67
- opts . Store . Add ( stdcol ) ;
68
- }
69
- }
70
-
71
- // remove standard columns
72
- var removeStd = config . GetSection ( "removeStandardColumns" ) ;
73
- if ( removeStd . GetChildren ( ) . Any ( ) )
74
- {
75
- foreach ( var col in removeStd . GetChildren ( ) . ToList ( ) )
76
- {
77
- if ( Enum . TryParse ( col . Value , ignoreCase : true , result : out StandardColumn stdcol )
78
- && opts . Store . Contains ( stdcol ) )
79
- opts . Store . Remove ( stdcol ) ;
80
- }
81
- }
82
- }
83
-
84
- void AddAdditionalColumns ( )
85
- {
86
- var newcols =
87
- config . GetSection ( "additionalColumns" ) . Get < List < SqlColumn > > ( )
88
- ?? config . GetSection ( "customColumns" ) . Get < List < SqlColumn > > ( ) ; // backwards-compatibility
89
-
90
- if ( newcols != null )
91
- {
92
- foreach ( var c in newcols )
93
- {
94
- if ( ! string . IsNullOrWhiteSpace ( c . ColumnName ) )
95
- {
96
- if ( opts . AdditionalColumns == null )
97
- opts . AdditionalColumns = new Collection < SqlColumn > ( ) ;
98
-
99
- opts . AdditionalColumns . Add ( c ) ;
100
- }
101
- }
102
- }
103
- }
104
-
105
- void ReadStandardColumns ( )
106
- {
107
- var section = config . GetSection ( "id" ) ;
108
- if ( section != null )
109
- {
110
- SetCommonColumnOptions ( opts . Id ) ;
111
- #pragma warning disable 618 // deprecated: BigInt property
112
- SetProperty . IfNotNull < bool > ( section [ "bigInt" ] , ( val ) => opts . Id . BigInt = val ) ;
113
- #pragma warning restore 618
114
- }
115
-
116
- section = config . GetSection ( "level" ) ;
117
- if ( section != null )
118
- {
119
- SetCommonColumnOptions ( opts . Level ) ;
120
- SetProperty . IfNotNull < bool > ( section [ "storeAsEnum" ] , ( val ) => opts . Level . StoreAsEnum = val ) ;
121
- }
122
-
123
- section = config . GetSection ( "properties" ) ;
124
- if ( section != null )
125
- {
126
- SetCommonColumnOptions ( opts . Properties ) ;
127
- SetProperty . IfNotNull < bool > ( section [ "excludeAdditionalProperties" ] , ( val ) => opts . Properties . ExcludeAdditionalProperties = val ) ;
128
- SetProperty . IfNotNull < string > ( section [ "dictionaryElementName" ] , ( val ) => opts . Properties . DictionaryElementName = val ) ;
129
- SetProperty . IfNotNull < string > ( section [ "itemElementName" ] , ( val ) => opts . Properties . ItemElementName = val ) ;
130
- SetProperty . IfNotNull < bool > ( section [ "omitDictionaryContainerElement" ] , ( val ) => opts . Properties . OmitDictionaryContainerElement = val ) ;
131
- SetProperty . IfNotNull < bool > ( section [ "omitSequenceContainerElement" ] , ( val ) => opts . Properties . OmitSequenceContainerElement = val ) ;
132
- SetProperty . IfNotNull < bool > ( section [ "omitStructureContainerElement" ] , ( val ) => opts . Properties . OmitStructureContainerElement = val ) ;
133
- SetProperty . IfNotNull < bool > ( section [ "omitElementIfEmpty" ] , ( val ) => opts . Properties . OmitElementIfEmpty = val ) ;
134
- SetProperty . IfNotNull < string > ( section [ "propertyElementName" ] , ( val ) => opts . Properties . PropertyElementName = val ) ;
135
- SetProperty . IfNotNull < string > ( section [ "rootElementName" ] , ( val ) => opts . Properties . RootElementName = val ) ;
136
- SetProperty . IfNotNull < string > ( section [ "sequenceElementName" ] , ( val ) => opts . Properties . SequenceElementName = val ) ;
137
- SetProperty . IfNotNull < string > ( section [ "structureElementName" ] , ( val ) => opts . Properties . StructureElementName = val ) ;
138
- SetProperty . IfNotNull < bool > ( section [ "usePropertyKeyAsElementName" ] , ( val ) => opts . Properties . UsePropertyKeyAsElementName = val ) ;
139
- // TODO PropertiesFilter would need a compiled Predicate<string> (high Roslyn overhead, see Serilog Config repo #106)
140
- }
141
-
142
- section = config . GetSection ( "timeStamp" ) ;
143
- if ( section != null )
144
- {
145
- SetCommonColumnOptions ( opts . TimeStamp ) ;
146
- SetProperty . IfNotNull < bool > ( section [ "convertToUtc" ] , ( val ) => opts . TimeStamp . ConvertToUtc = val ) ;
147
- }
148
-
149
- section = config . GetSection ( "logEvent" ) ;
150
- if ( section != null )
151
- {
152
- SetCommonColumnOptions ( opts . LogEvent ) ;
153
- SetProperty . IfNotNull < bool > ( section [ "excludeAdditionalProperties" ] , ( val ) => opts . LogEvent . ExcludeAdditionalProperties = val ) ;
154
- SetProperty . IfNotNull < bool > ( section [ "ExcludeStandardColumns" ] , ( val ) => opts . LogEvent . ExcludeStandardColumns = val ) ;
155
- }
156
-
157
- section = config . GetSection ( "message" ) ;
158
- if ( section != null )
159
- SetCommonColumnOptions ( opts . Message ) ;
160
-
161
- section = config . GetSection ( "exception" ) ;
162
- if ( section != null )
163
- SetCommonColumnOptions ( opts . Exception ) ;
164
-
165
- section = config . GetSection ( "messageTemplate" ) ;
166
- if ( section != null )
167
- SetCommonColumnOptions ( opts . MessageTemplate ) ;
168
-
169
- // Standard Columns are subclasses of the SqlColumn class
170
- void SetCommonColumnOptions ( SqlColumn target )
171
- {
172
- SetProperty . IfNotNullOrEmpty < string > ( section [ "columnName" ] , ( val ) => target . ColumnName = val ) ;
173
- SetProperty . IfNotNull < string > ( section [ "dataType" ] , ( val ) => target . SetDataTypeFromConfigString ( val ) ) ;
174
- SetProperty . IfNotNull < bool > ( section [ "allowNull" ] , ( val ) => target . AllowNull = val ) ;
175
- SetProperty . IfNotNull < int > ( section [ "dataLength" ] , ( val ) => target . DataLength = val ) ;
176
- SetProperty . IfNotNull < bool > ( section [ "nonClusteredIndex" ] , ( val ) => target . NonClusteredIndex = val ) ;
177
- }
178
- }
179
-
180
- void ReadMiscColumnOptions ( )
181
- {
182
- SetProperty . IfNotNull < bool > ( config [ "disableTriggers" ] , ( val ) => opts . DisableTriggers = val ) ;
183
- SetProperty . IfNotNull < bool > ( config [ "clusteredColumnstoreIndex" ] , ( val ) => opts . ClusteredColumnstoreIndex = val ) ;
184
-
185
- string pkName = config [ "primaryKeyColumnName" ] ;
186
- if ( ! string . IsNullOrEmpty ( pkName ) )
187
- {
188
- if ( opts . ClusteredColumnstoreIndex )
189
- throw new ArgumentException ( "SQL Clustered Columnstore Indexes and primary key constraints are mutually exclusive." ) ;
190
-
191
- foreach ( var standardCol in opts . Store )
192
- {
193
- var stdColOpts = opts . GetStandardColumnOptions ( standardCol ) ;
194
- if ( pkName . Equals ( stdColOpts . ColumnName , StringComparison . InvariantCultureIgnoreCase ) )
195
- {
196
- opts . PrimaryKey = stdColOpts ;
197
- break ;
198
- }
199
- }
200
-
201
- if ( opts . PrimaryKey == null && opts . AdditionalColumns != null )
202
- {
203
- foreach ( var col in opts . AdditionalColumns )
204
- {
205
- if ( pkName . Equals ( col . ColumnName , StringComparison . InvariantCultureIgnoreCase ) )
206
- {
207
- opts . PrimaryKey = col ;
208
- break ;
209
- }
210
- }
211
- }
212
-
213
- if ( opts . PrimaryKey == null )
214
- throw new ArgumentException ( $ "Could not match the configured primary key column name \" { pkName } \" with a data column in the table.") ;
215
- }
216
- }
217
- }
31
+ internal static ColumnOptions ConfigureColumnOptions ( ColumnOptions columnOptions , IConfigurationSection config ) =>
32
+ ColumnOptionsProvider . ConfigureColumnOptions ( columnOptions , config ) ;
218
33
}
219
34
}
0 commit comments