@@ -13,8 +13,8 @@ static class SettingsAttributeReader
1313{
1414 public static Settings Read ( string assemblyPath )
1515 {
16- Settings ? settings = null ;
17- List < SagaDefinition > sagas = [ ] ;
16+ List < SagaDefinition > sagaDefinitions = [ ] ;
17+ Dictionary < string , object ? > ? properties = null ;
1818
1919 using var stream = File . OpenRead ( assemblyPath ) ;
2020 using var peReader = new PEReader ( stream ) ;
@@ -37,8 +37,12 @@ public static Settings Read(string assemblyPath)
3737 if ( attNamespace == "NServiceBus.Persistence.Sql" )
3838 {
3939 var args = attribute . DecodeValue ( AttributeTypeProvider . Instance ) ;
40- var properties = args . NamedArguments . ToDictionary ( o => o . Name ! , o => o . Value ) ;
41- settings = ReadFromProperties ( properties ) ;
40+ // This assembly level attribute can only exists once per assembly. This is an additional safe guard to make this code more intention revealing
41+ if ( properties is not null )
42+ {
43+ throw new InvalidOperationException ( "Only one SqlPersistenceSettingsAttribute can be defined per assembly" ) ;
44+ }
45+ properties = args . NamedArguments . ToDictionary ( o => o . Name ! , o => o . Value ) ;
4246 }
4347 }
4448 }
@@ -54,48 +58,43 @@ public static Settings Read(string assemblyPath)
5458 if ( string . IsNullOrEmpty ( attNamespace ) )
5559 {
5660 var args = attribute . DecodeValue ( AttributeTypeProvider . Instance ) ;
57- var properties = args . NamedArguments . ToDictionary ( o => o . Name ! , o => o . Value ) ;
61+ var sagaProperties = args . NamedArguments . ToDictionary ( o => o . Name ! , o => o . Value ) ;
5862
59- var sagaType = properties . GetValueOrDefault ( "SagaType" ) as string ;
60- var corrName = properties . GetValueOrDefault ( "CorrelationPropertyName" ) as string ;
61- var corrType = properties . GetValueOrDefault ( "CorrelationPropertyType" ) as string ;
62- var transName = properties . GetValueOrDefault ( "TransitionalCorrelationPropertyName" ) as string ;
63- var transType = properties . GetValueOrDefault ( "TransitionalCorrelationPropertyType" ) as string ;
64- var tableSuffix = properties . GetValueOrDefault ( "TableSuffix" ) as string ;
63+ var sagaType = sagaProperties . GetValueOrDefault ( "SagaType" ) as string ;
64+ var corrName = sagaProperties . GetValueOrDefault ( "CorrelationPropertyName" ) as string ;
65+ var corrType = sagaProperties . GetValueOrDefault ( "CorrelationPropertyType" ) as string ;
66+ var transName = sagaProperties . GetValueOrDefault ( "TransitionalCorrelationPropertyName" ) as string ;
67+ var transType = sagaProperties . GetValueOrDefault ( "TransitionalCorrelationPropertyType" ) as string ;
68+ var tableSuffix = sagaProperties . GetValueOrDefault ( "TableSuffix" ) as string ;
6569
6670 var correlation = GetCorrelation ( corrName , corrType ) ;
6771 var transitionalCorrelation = GetCorrelation ( transName , transType ) ;
6872
6973 if ( tableSuffix is not null && sagaType is not null )
7074 {
7175 var definition = new SagaDefinition ( tableSuffix , sagaType , correlation , transitionalCorrelation ) ;
72- sagas . Add ( definition ) ;
76+ sagaDefinitions . Add ( definition ) ;
7377 }
7478 }
7579 }
7680 }
7781 }
7882
7983 // If no attribute, generate the default
80- settings ??= ReadFromProperties ( [ ] ) ;
81-
82- // Then apply the saga definitions
83- settings . SagaDefinitions = sagas ;
84- return settings ;
84+ return ReadFromProperties ( properties ?? [ ] , sagaDefinitions ) ;
8585 }
8686
87- public static Settings ReadFromProperties ( Dictionary < string , object ? > properties )
88- {
89- return new Settings
87+ public static Settings ReadFromProperties ( Dictionary < string , object ? > properties , IReadOnlyCollection < SagaDefinition > sagas ) =>
88+ new ( )
9089 {
9190 BuildDialects = ReadBuildDialects ( properties ) . ToList ( ) ,
9291 ScriptPromotionPath = ReadScriptPromotionPath ( properties ) ,
9392 ProduceSagaScripts = GetBoolProperty ( properties , "ProduceSagaScripts" , true ) ,
9493 ProduceTimeoutScripts = GetBoolProperty ( properties , "ProduceTimeoutScripts" , true ) ,
9594 ProduceSubscriptionScripts = GetBoolProperty ( properties , "ProduceSubscriptionScripts" , true ) ,
9695 ProduceOutboxScripts = GetBoolProperty ( properties , "ProduceOutboxScripts" , true ) ,
96+ SagaDefinitions = sagas
9797 } ;
98- }
9998
10099 static bool GetBoolProperty ( Dictionary < string , object ? > properties , string key , bool defaultValue = false )
101100 => properties . GetValueOrDefault ( key ) as bool ? ?? defaultValue ;
@@ -157,12 +156,7 @@ static IEnumerable<BuildSqlDialect> ReadBuildDialects(Dictionary<string, object?
157156 return null ;
158157 }
159158
160- if ( ! Enum . TryParse < CorrelationPropertyType > ( type , out var propType ) )
161- {
162- throw new Exception ( $ "Invalid correlation property type '{ type } ' found in metadata attribute.") ;
163- }
164-
165- return new CorrelationProperty ( name , propType ) ;
159+ return ! Enum . TryParse < CorrelationPropertyType > ( type , out var propType ) ? throw new Exception ( $ "Invalid correlation property type '{ type } ' found in metadata attribute.") : new CorrelationProperty ( name , propType ) ;
166160 }
167161
168162 // Minimal implementation that only supports primitive types
@@ -172,8 +166,8 @@ sealed class AttributeTypeProvider : ICustomAttributeTypeProvider<object?>
172166
173167 public static readonly AttributeTypeProvider Instance = new ( ) ;
174168
175- public object ? GetPrimitiveType ( PrimitiveTypeCode typeCode ) => typeCode ;
176- public object ? GetSystemType ( ) => typeof ( Type ) ;
169+ public object GetPrimitiveType ( PrimitiveTypeCode typeCode ) => typeCode ;
170+ public object GetSystemType ( ) => typeof ( Type ) ;
177171 public object ? GetTypeFromDefinition ( MetadataReader r , TypeDefinitionHandle h , byte raw ) => null ;
178172 public object ? GetTypeFromReference ( MetadataReader r , TypeReferenceHandle h , byte raw ) => null ;
179173 public object ? GetSZArrayType ( object ? elementType ) => null ;
0 commit comments