@@ -573,10 +573,389 @@ public class FileOptions
573573
574574---
575575
576+ # Performance: IOptionsSnapshot vs IOptionsMonitor
577+
578+ <div class =" columns " >
579+ <div >
580+
581+ ## <i class =" fa fa-camera " ></i > IOptionsSnapshot< ; T> ;
582+
583+ - ** Scoped lifetime** (per request)
584+ - ** Recomputed each request**
585+ - ** Supports named options**
586+ - ** Best for web apps**
587+
588+ ``` csharp
589+ public class MyController : Controller
590+ {
591+ public MyController (IOptionsSnapshot <MyOptions > options )
592+ {
593+ // Fresh config per request
594+ _options = options .Value ;
595+ }
596+ }
597+ ```
598+
599+ </div >
600+ <div >
601+
602+ ## <i class =" fa fa-tv " ></i > IOptionsMonitor< ; T> ;
603+
604+ - ** Singleton lifetime**
605+ - ** Real-time change notifications**
606+ - ** Supports named options**
607+ - ** Best for background services**
608+
609+ ``` csharp
610+ public class MyService : BackgroundService
611+ {
612+ public MyService (IOptionsMonitor <MyOptions > monitor )
613+ {
614+ // React to config changes
615+ monitor .OnChange (OnConfigChanged );
616+ }
617+ }
618+ ```
619+
620+ </div >
621+ </div >
622+
623+ ---
624+
625+ # Testing Configuration
626+
627+ ---
628+
629+ # Configuration Testing Patterns
630+
631+ <div class =" columns " >
632+ <div >
633+
634+ ## <i class =" fa fa-flask " ></i > Unit Testing
635+
636+ ``` csharp
637+ [Test ]
638+ public void Service_Uses_Configuration_Correctly ()
639+ {
640+ // Arrange
641+ var config = new ConfigurationBuilder ()
642+ .AddInMemoryCollection (new []
643+ {
644+ new KeyValuePair <string , string >(" ApiUrl" , " https://test.api" ),
645+ new KeyValuePair <string , string >(" Timeout" , " 30" )
646+ })
647+ .Build ();
648+
649+ var options = Options .Create (config .Get <ApiOptions >());
650+ var service = new ApiService (options );
651+
652+ // Act & Assert
653+ Assert .That (service .BaseUrl , Is .EqualTo (" https://test.api" ));
654+ }
655+ ```
656+
657+ </div >
658+ <div >
659+
660+ ## <i class =" fa fa-cog " ></i > Integration Testing
661+
662+ ``` csharp
663+ public class TestWebApplicationFactory <TProgram >
664+ : WebApplicationFactory <TProgram > where TProgram : class
665+ {
666+ protected override void ConfigureWebHost (IWebHostBuilder builder )
667+ {
668+ builder .ConfigureAppConfiguration (config =>
669+ {
670+ config .AddInMemoryCollection (new []
671+ {
672+ new KeyValuePair <string , string >(" Database:ConnectionString" ,
673+ " Server=localhost;Database=TestDb;" ),
674+ new KeyValuePair <string , string >(" ExternalApi:BaseUrl" ,
675+ " https://mock-api.test" )
676+ });
677+ });
678+ }
679+ }
680+ ```
681+
682+ </div >
683+ </div >
684+
685+ ---
686+
687+ # Configuration Validation
688+
689+ <div class =" columns " >
690+ <div >
691+
692+ ## <i class =" fa fa-check-circle " ></i > Data Annotations
693+
694+ ``` csharp
695+ public class DatabaseOptions
696+ {
697+ [Required ]
698+ [Url ]
699+ public string ConnectionString { get ; set ; } = " " ;
700+
701+ [Range (1 , 300 )]
702+ public int CommandTimeoutSeconds { get ; set ; } = 30 ;
703+
704+ [Required ]
705+ [RegularExpression (@" ^[a-zA-Z0-9_]+$" )]
706+ public string DatabaseName { get ; set ; } = " " ;
707+ }
708+
709+ // Register with validation
710+ services .AddOptions <DatabaseOptions >()
711+ .Bind (configuration .GetSection (" Database" ))
712+ .ValidateDataAnnotations ()
713+ .ValidateOnStart ();
714+ ```
715+
716+ </div >
717+ <div >
718+
719+ ## <i class =" fa fa-shield-alt " ></i > Custom Validation
720+
721+ ``` csharp
722+ public class DatabaseOptionsValidator : IValidateOptions <DatabaseOptions >
723+ {
724+ public ValidateOptionsResult Validate (string name , DatabaseOptions options )
725+ {
726+ var failures = new List <string >();
727+
728+ if (string .IsNullOrEmpty (options .ConnectionString ))
729+ failures .Add (" ConnectionString is required" );
730+
731+ if (options .CommandTimeoutSeconds <= 0 )
732+ failures .Add (" CommandTimeoutSeconds must be positive" );
733+
734+ if (! IsValidDatabaseName (options .DatabaseName ))
735+ failures .Add (" Invalid database name format" );
736+
737+ return failures .Count > 0
738+ ? ValidateOptionsResult .Fail (failures )
739+ : ValidateOptionsResult .Success ;
740+ }
741+ }
742+
743+ // Register validator
744+ services .AddSingleton <IValidateOptions <DatabaseOptions >, DatabaseOptionsValidator >();
745+ ```
746+
747+ </div >
748+ </div >
749+
750+ ---
751+
752+ # Validation at Startup
753+
754+ <div class =" columns " >
755+ <div >
756+
757+ ## <i class =" fa fa-rocket " ></i > Fail Fast Pattern
758+
759+ ``` csharp
760+ // Program.cs
761+ var builder = WebApplication .CreateBuilder (args );
762+
763+ // Configure options with validation
764+ builder .Services .AddOptions <ApiOptions >()
765+ .Bind (builder .Configuration .GetSection (" Api" ))
766+ .ValidateDataAnnotations ()
767+ .ValidateOnStart (); // Validates during app startup
768+
769+ builder .Services .AddOptions <DatabaseOptions >()
770+ .Bind (builder .Configuration .GetSection (" Database" ))
771+ .Validate (options => ! string .IsNullOrEmpty (options .ConnectionString ),
772+ " Connection string cannot be empty" )
773+ .ValidateOnStart ();
774+
775+ var app = builder .Build ();
776+ // App fails to start if validation fails
777+ ```
778+
779+ </div >
780+ <div >
781+
782+ ## <i class =" fa fa-exclamation-triangle " ></i > Benefits
783+
784+ - ** Early Detection** : Catch configuration errors at startup
785+ - ** Clear Error Messages** : Know exactly what's wrong
786+ - ** Prevents Runtime Failures** : No surprises in production
787+ - ** Better DevEx** : Immediate feedback during development
788+
789+ ``` csharp
790+ // Custom validation method
791+ services .AddOptions <MyOptions >()
792+ .Bind (configuration .GetSection (" MySection" ))
793+ .Validate (options =>
794+ {
795+ return options .ApiKey ? .Length >= 10 ;
796+ }, " ApiKey must be at least 10 characters" )
797+ .ValidateOnStart ();
798+ ```
799+
800+ </div >
801+ </div >
802+
803+ ---
804+
576805# DEMOS
577806
578807---
579808
809+ # Secrets Management Best Practices
810+
811+ <div class =" columns " >
812+ <div >
813+
814+ ## <i class =" fa fa-exclamation-triangle " ></i > Don't
815+
816+ - Store secrets in appsettings.json
817+ - Commit secrets to source control
818+ - Use production secrets in development
819+ - Log configuration values containing secrets
820+
821+ </div >
822+ <div >
823+
824+ ## <i class =" fa fa-check-circle " ></i > Do
825+
826+ - Use User Secrets for development
827+ - Use Azure Key Vault for production
828+ - Use environment variables for containers
829+ - Implement proper secret rotation
830+ - Validate secrets at startup
831+
832+ </div >
833+ </div >
834+
835+ ---
836+
837+ # Secrets by Environment
838+
839+ <div class =" columns3 " >
840+ <div >
841+
842+ ## <i class =" fa fa-laptop-code " ></i > Development
843+
844+ - ** User Secrets**
845+ - Per-project secrets
846+ - Stored outside source control
847+ - Easy to manage locally
848+
849+ ``` bash
850+ dotnet user-secrets set " ApiKey" " dev-key-123"
851+ ```
852+
853+ </div >
854+ <div >
855+
856+ ## <i class =" fa fa-server " ></i > Staging/Production
857+
858+ - ** Azure Key Vault**
859+ - Centralized secret management
860+ - Access policies and RBAC
861+ - Audit logging
862+ - Automatic rotation
863+
864+ ``` csharp
865+ builder .Configuration .AddAzureKeyVault (
866+ keyVaultUrl , credential );
867+ ```
868+
869+ </div >
870+ <div >
871+
872+ ## <i class =" fa fa-cube " ></i > Containers
873+
874+ - ** Environment Variables**
875+ - Kubernetes secrets
876+ - Docker secrets
877+ - Service connection strings
878+
879+ ``` bash
880+ docker run -e " ConnectionString=..." myapp
881+ ```
882+
883+ </div >
884+ </div >
885+
886+ ---
887+
888+ # Environment-Specific Configuration Strategies
889+
890+ <div class =" columns " >
891+ <div >
892+
893+ ## <i class =" fa fa-layer-group " ></i > Layered Configuration
894+
895+ ``` csharp
896+ builder .Configuration
897+ .AddJsonFile (" appsettings.json" )
898+ .AddJsonFile ($" appsettings.{env .EnvironmentName }.json" , true )
899+ .AddEnvironmentVariables ()
900+ .AddCommandLine (args );
901+ ```
902+
903+ ** Order matters!** Later sources override earlier ones.
904+
905+ </div >
906+ <div >
907+
908+ ## <i class =" fa fa-code-branch " ></i > Environment Patterns
909+
910+ - ** Development** : User Secrets + local files
911+ - ** Staging** : Environment variables + Key Vault
912+ - ** Production** : Key Vault + minimal env vars
913+ - ** Testing** : In-memory configuration
914+
915+ ``` csharp
916+ if (env .IsDevelopment ())
917+ {
918+ builder .Configuration .AddUserSecrets <Program >();
919+ }
920+ ```
921+
922+ </div >
923+ </div >
924+
925+ ---
926+
927+ # Configuration Security Considerations
928+
929+ <div class =" columns " >
930+ <div >
931+
932+ ## <i class =" fa fa-shield-alt " ></i > Prevent Secret Leakage
933+
934+ - ** Never log IConfiguration directly**
935+ - ** Redact sensitive values in logs**
936+ - ** Use IOptionsSnapshot/IOptionsMonitor**
937+ - ** Implement custom configuration providers for sensitive data**
938+
939+ </div >
940+ <div >
941+
942+ ## <i class =" fa fa-eye-slash " ></i > Secure Logging
943+
944+ ``` csharp
945+ // ❌ DON'T - Exposes all configuration
946+ logger .LogInformation (" Config: {Config}" ,
947+ JsonSerializer .Serialize (configuration ));
948+
949+ // ✅ DO - Log specific, non-sensitive values
950+ logger .LogInformation (" Database timeout: {Timeout}s" ,
951+ dbOptions .CommandTimeout );
952+ ```
953+
954+ </div >
955+ </div >
956+
957+ ---
958+
580959# Questions?
581960
582961---
0 commit comments