{"id":1299,"date":"2026-03-16T21:45:28","date_gmt":"2026-03-17T00:45:28","guid":{"rendered":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/"},"modified":"2026-03-16T21:45:28","modified_gmt":"2026-03-17T00:45:28","slug":"patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor","status":"publish","type":"post","link":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/","title":{"rendered":"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados"},"content":{"rendered":"\n<p>Una de las cosas que m\u00e1s me molestaba cuando empec\u00e9 a trabajar con .NET era ver c\u00f3digo lleno de <code>configuration[\"Email:SmtpServer\"]<\/code> disperso por todos lados. Magic strings por ac\u00e1, magic strings por all\u00e1. Si el nombre de la clave cambiaba en el JSON, el error aparec\u00eda en runtime y solo si ese c\u00f3digo en particular se ejecutaba. El <strong>Patr\u00f3n Options<\/strong> resuelve exactamente eso: configuraci\u00f3n fuertemente tipada, validada y con soporte para recarga en caliente. En este art\u00edculo explico las tres interfaces principales y c\u00f3mo elegir la correcta para cada situaci\u00f3n.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u00bfQu\u00e9 es el Patr\u00f3n Options?<\/h2>\n\n\n\n<p>El Patr\u00f3n Options (en <code>Microsoft.Extensions.Options<\/code>) es el est\u00e1ndar arquitect\u00f3nico de .NET para manejar configuraciones. En lugar de acceder a valores por nombre de cadena, mape\u00e1s secciones de <code>appsettings.json<\/code> o variables de entorno a clases C# tipadas (POCOs). Ganas autocompletado en el IDE, refactoring seguro y la posibilidad de validar la configuraci\u00f3n antes de que la app arranque.<\/p>\n\n\n\n<p>.NET provee tres interfaces para diferentes necesidades de ciclo de vida y recarga:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n  <li><strong>IOptions&lt;T&gt;<\/strong> \u2192 Singleton, configuraci\u00f3n est\u00e1tica<\/li>\n  <li><strong>IOptionsSnapshot&lt;T&gt;<\/strong> \u2192 Scoped, recarga por request<\/li>\n  <li><strong>IOptionsMonitor&lt;T&gt;<\/strong> \u2192 Singleton, recarga en tiempo real con eventos<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. IOptions&lt;T&gt;: El caso base<\/h2>\n\n\n\n<p>La implementaci\u00f3n m\u00e1s simple. Se registra como <strong>Singleton<\/strong>: la configuraci\u00f3n se lee una sola vez al arrancar la app y se cachea. Ideal para valores que no van a cambiar mientras la aplicaci\u00f3n corre \u2014 credenciales de base de datos, configuraci\u00f3n de email, endpoints de terceros fijos.<\/p>\n\n\n\n<p><strong>Limitaci\u00f3n clave:<\/strong> si el <code>appsettings.json<\/code> cambia mientras la app corre, <code>IOptions&lt;T&gt;<\/code> no lo va a ver hasta el pr\u00f3ximo reinicio.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Modelo fuertemente tipado\npublic class EmailSettings\n{\n    public const string SectionName = \"Email\";\n    public string SmtpServer { get; set; } = string.Empty;\n    public int Port { get; set; }\n}\n\n\/\/ Registro en Program.cs\nbuilder.Services.Configure&lt;EmailSettings&gt;(\n    builder.Configuration.GetSection(EmailSettings.SectionName));\n\n\/\/ Uso en un servicio (Primary Constructor C# 12+)\npublic class EmailService(IOptions&lt;EmailSettings&gt; options)\n{\n    \/\/ .Value se eval\u00faa una sola vez y se cachea (es Singleton)\n    private readonly EmailSettings _settings = options.Value;\n\n    public void SendEmail()\n    {\n        Console.WriteLine($\"Conectando a {_settings.SmtpServer}:{_settings.Port}...\");\n    }\n}<\/code><\/pre>\n\n\n\n<p>La constante <code>SectionName<\/code> dentro de la clase es un patr\u00f3n que adopt\u00e9 hace tiempo: elimina la magic string del registro y centraliza el nombre de la secci\u00f3n junto a su definici\u00f3n.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. IOptionsSnapshot&lt;T&gt;: Recarga por Request<\/h2>\n\n\n\n<p>Se registra como <strong>Scoped<\/strong> \u2014 una instancia por request HTTP (o por scope de DI). Cada vez que se crea un nuevo scope, lee la configuraci\u00f3n m\u00e1s reciente. Pero dentro del mismo scope, el valor es inmutable. Esto es clave: garantiza consistencia durante el procesamiento de un request, sin que un cambio de configuraci\u00f3n a mitad de camino rompa la l\u00f3gica.<\/p>\n\n\n\n<p><strong>Trampa com\u00fan \u2014 Captive Dependency:<\/strong> nunca inyectar <code>IOptionsSnapshot&lt;T&gt;<\/code> en un servicio Singleton. El Singleton \u00abcaptura\u00bb la instancia Scoped y la mantiene viva m\u00e1s all\u00e1 de su ciclo de vida esperado, lo que puede generar valores desactualizados o excepciones.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class FeatureFlagService(IOptionsSnapshot&lt;FeatureFlagsSettings&gt; options)\n{\n    \/\/ Cada nuevo request HTTP obtiene la configuraci\u00f3n m\u00e1s reciente.\n    \/\/ Durante este request completo, _settings no cambia.\n    private readonly FeatureFlagsSettings _settings = options.Value;\n\n    public void ExecuteFeature()\n    {\n        if (_settings.IsNewFeatureEnabled)\n        {\n            Console.WriteLine(\"Ejecutando la nueva caracter\u00edstica...\");\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Este es el que uso para Feature Flags en combinaci\u00f3n con <code>Microsoft.FeatureManagement<\/code>: cambio el valor en el archivo de configuraci\u00f3n y el siguiente request ya lo toma, sin reiniciar nada.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. IOptionsMonitor&lt;T&gt;: Hot Reload en Servicios Singleton<\/h2>\n\n\n\n<p>La interfaz m\u00e1s din\u00e1mica. Se registra como <strong>Singleton<\/strong> y permite dos cosas que las anteriores no pueden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n  <li><strong>CurrentValue:<\/strong> acceso a la configuraci\u00f3n m\u00e1s reciente en cualquier momento<\/li>\n  <li><strong>OnChange():<\/strong> suscripci\u00f3n a eventos cuando la configuraci\u00f3n cambia<\/li>\n<\/ul>\n\n\n\n<p>Es la opci\u00f3n correcta para <code>BackgroundService<\/code>, <code>IHostedService<\/code> o cualquier servicio Singleton que necesite reaccionar a cambios de configuraci\u00f3n en tiempo real.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class BackgroundProcessor : IDisposable\n{\n    private readonly IOptionsMonitor&lt;ProcessingSettings&gt; _optionsMonitor;\n    private readonly IDisposable? _changeSubscription;\n    private ProcessingSettings _currentSettings;\n\n    public BackgroundProcessor(IOptionsMonitor&lt;ProcessingSettings&gt; optionsMonitor)\n    {\n        _optionsMonitor = optionsMonitor;\n        _currentSettings = _optionsMonitor.CurrentValue;\n\n        \/\/ Suscripci\u00f3n al evento de cambio\n        _changeSubscription = _optionsMonitor.OnChange(newSettings =>\n        {\n            Console.WriteLine(\"\u00a1La configuraci\u00f3n cambi\u00f3 en tiempo real!\");\n            _currentSettings = newSettings;\n        });\n    }\n\n    public void Process()\n    {\n        Console.WriteLine($\"Procesando con l\u00edmite de {_currentSettings.BatchSize} items.\");\n    }\n\n    public void Dispose()\n    {\n        \/\/ Importante: liberar la suscripci\u00f3n para evitar memory leaks\n        _changeSubscription?.Dispose();\n    }\n}<\/code><\/pre>\n\n\n\n<p>El <code>Dispose()<\/code> no es opcional. Si no liber\u00e1s la suscripci\u00f3n de <code>OnChange()<\/code>, el callback mantiene una referencia al objeto vivo m\u00e1s all\u00e1 de su ciclo de vida y ten\u00e9s un memory leak. Lo aprend\u00ed a las malas en un BackgroundService que crec\u00eda en memoria de forma constante hasta que el proceso era reciclado.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cuadro comparativo: \u00bfCu\u00e1l usar?<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Interfaz<\/th><th>Ciclo de vida<\/th><th>Hot Reload<\/th><th>Cu\u00e1ndo usarla<\/th><\/tr><\/thead><tbody><tr><td><code>IOptions&lt;T&gt;<\/code><\/td><td>Singleton<\/td><td>&#x274c; No<\/td><td>Configuraci\u00f3n est\u00e1tica (DB, endpoints fijos)<\/td><\/tr><tr><td><code>IOptionsSnapshot&lt;T&gt;<\/code><\/td><td>Scoped<\/td><td>&#x2705; Por request<\/td><td>Feature flags, configuraci\u00f3n que cambia entre requests<\/td><\/tr><tr><td><code>IOptionsMonitor&lt;T&gt;<\/code><\/td><td>Singleton<\/td><td>&#x2705; Tiempo real<\/td><td>BackgroundServices, servicios que reaccionan a cambios<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Validaci\u00f3n Moderna: Fail Fast con ValidateOnStart y Source Generators<\/h2>\n\n\n\n<p>Desde .NET 8, el patr\u00f3n Options se complementa con validaci\u00f3n en tiempo de compilaci\u00f3n. El problema que resuelve: si falta una clave cr\u00edtica en la configuraci\u00f3n, \u00bfprefer\u00eds enterarte al arrancar la app o cuando ese c\u00f3digo se ejecuta por primera vez en producci\u00f3n a las 2 AM?<\/p>\n\n\n\n<p><code>ValidateOnStart()<\/code> hace que la app falle inmediatamente al arrancar si la configuraci\u00f3n no es v\u00e1lida. Los <strong>Source Generators<\/strong> con <code>[OptionsValidator]<\/code> generan el c\u00f3digo de validaci\u00f3n en tiempo de compilaci\u00f3n, sin reflexi\u00f3n en runtime.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Configuraci\u00f3n moderna en Program.cs (patr\u00f3n recomendado desde .NET 8)\nbuilder.Services.AddOptions&lt;EmailSettings&gt;()\n    .BindConfiguration(EmailSettings.SectionName)\n    .ValidateDataAnnotations()\n    .ValidateOnStart(); \/\/ Falla al arrancar si la config es inv\u00e1lida\n\n\/\/ Modelo con validaciones\npublic class EmailSettings\n{\n    public const string SectionName = \"Email\";\n\n    [Required]\n    public string SmtpServer { get; set; } = string.Empty;\n\n    [Range(1, 65535)]\n    public int Port { get; set; }\n}\n\n\/\/ Source Generator para validaci\u00f3n sin reflexi\u00f3n (recomendado para AOT y alto rendimiento)\n[OptionsValidator]\npublic partial class EmailSettingsValidator : IValidateOptions&lt;EmailSettings&gt; { }<\/code><\/pre>\n\n\n\n<p>Esta combinaci\u00f3n es la que uso en todos los proyectos nuevos. Si el archivo de configuraci\u00f3n del entorno de staging tiene un typo o falta una clave, el pipeline de CI lo detecta en el startup del smoke test, no en producci\u00f3n.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusi\u00f3n<\/h2>\n\n\n\n<p>El Patr\u00f3n Options no es un detalle menor \u2014 es la base de una configuraci\u00f3n robusta en .NET. La elecci\u00f3n entre las tres interfaces no es arbitraria: depende del ciclo de vida de tu servicio y de si necesit\u00e1s que la configuraci\u00f3n se actualice en caliente. La regla pr\u00e1ctica: si tu servicio es Singleton y necesita reaccionar a cambios, us\u00e1 <code>IOptionsMonitor&lt;T&gt;<\/code>. Si es Scoped (un controller, un servicio de request), us\u00e1 <code>IOptionsSnapshot&lt;T&gt;<\/code>. Si la configuraci\u00f3n no cambia nunca, <code>IOptions&lt;T&gt;<\/code> es suficiente y m\u00e1s eficiente.<\/p>\n\n\n\n<p>Y si todav\u00eda us\u00e1s <code>IConfiguration<\/code> directamente con magic strings \u2014 este es el momento de migrar. No es una refactorizaci\u00f3n grande, y el beneficio en mantenibilidad vale la pena.<\/p>\n\n\n\n<p>\u00bfQuer\u00e9s que profundice en la validaci\u00f3n con Source Generators para escenarios AOT o en c\u00f3mo combinar este patr\u00f3n con Azure App Configuration? Dejalo en los comentarios.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Gu\u00eda completa del Patr\u00f3n Options en .NET hasta .NET 10: diferencias entre IOptions, IOptionsSnapshot e IOptionsMonitor, cu\u00e1ndo usar cada uno, la trampa de Captive Dependency, y validaci\u00f3n moderna con ValidateOnStart y Source Generators. Con ejemplos reales y tabla comparativa.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1,202],"tags":[348,407,374,408,410,375,402,403,379,401,406,409,405,404],"class_list":["post-1299","post","type-post","status-publish","format-standard","hentry","category-blog","category-dotnet","tag-net-10","tag-backgroundservice","tag-configuracion","tag-dependency-injection","tag-fail-fast","tag-hot-reload","tag-ioptions","tag-ioptionsmonitor","tag-ioptionssnapshot","tag-options-pattern","tag-optionsvalidator","tag-poco","tag-source-generators","tag-validateonstart"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados &#183; devops Mauro Bernal<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados &#183; devops Mauro Bernal\" \/>\n<meta property=\"og:description\" content=\"Gu\u00eda completa del Patr\u00f3n Options en .NET hasta .NET 10: diferencias entre IOptions, IOptionsSnapshot e IOptionsMonitor, cu\u00e1ndo usar cada uno, la trampa de Captive Dependency, y validaci\u00f3n moderna con ValidateOnStart y Source Generators. Con ejemplos reales y tabla comparativa.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/\" \/>\n<meta property=\"og:site_name\" content=\"devops Mauro Bernal\" \/>\n<meta property=\"article:published_time\" content=\"2026-03-17T00:45:28+00:00\" \/>\n<meta name=\"author\" content=\"Mauro Bernal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@_maurobernal\" \/>\n<meta name=\"twitter:site\" content=\"@_maurobernal\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Mauro Bernal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\\\/\"},\"author\":{\"name\":\"Mauro Bernal\",\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/#\\\/schema\\\/person\\\/09c4dbdfb59b20e015c703fd19713283\"},\"headline\":\"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados\",\"datePublished\":\"2026-03-17T00:45:28+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\\\/\"},\"wordCount\":935,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/#\\\/schema\\\/person\\\/09c4dbdfb59b20e015c703fd19713283\"},\"keywords\":[\".NET 10\",\"BackgroundService\",\"Configuracion\",\"Dependency Injection\",\"Fail Fast\",\"Hot Reload\",\"IOptions\",\"IOptionsMonitor\",\"IOptionsSnapshot\",\"Options Pattern\",\"OptionsValidator\",\"POCO\",\"Source Generators\",\"ValidateOnStart\"],\"articleSection\":[\"Blog\",\"DotNet\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\\\/\",\"url\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\\\/\",\"name\":\"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados &#183; devops Mauro Bernal\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/#website\"},\"datePublished\":\"2026-03-17T00:45:28+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Portada\",\"item\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/\",\"name\":\"devops Mauro Bernal\",\"description\":\"Cuando tu trabajo es hacer que las cosas funcionen bien...\",\"publisher\":{\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/#\\\/schema\\\/person\\\/09c4dbdfb59b20e015c703fd19713283\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/maurobernal.com.ar\\\/blog\\\/#\\\/schema\\\/person\\\/09c4dbdfb59b20e015c703fd19713283\",\"name\":\"Mauro Bernal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/i0.wp.com\\\/maurobernal.com.ar\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/07\\\/logo-maurobernal.png?fit=1740%2C1740&ssl=1\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/maurobernal.com.ar\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/07\\\/logo-maurobernal.png?fit=1740%2C1740&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/maurobernal.com.ar\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/07\\\/logo-maurobernal.png?fit=1740%2C1740&ssl=1\",\"width\":1740,\"height\":1740,\"caption\":\"Mauro Bernal\"},\"logo\":{\"@id\":\"https:\\\/\\\/i0.wp.com\\\/maurobernal.com.ar\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/07\\\/logo-maurobernal.png?fit=1740%2C1740&ssl=1\"},\"description\":\"Desarrollo de Sistemas en .Net, IT Callcenters, DBA de SQL Server, Mikrotik, Pentest y T\u00e9cnico consultor de Sistemas Bejerman\",\"sameAs\":[\"https:\\\/\\\/maurobernal.com.ar\",\"https:\\\/\\\/x.com\\\/_maurobernal\",\"https:\\\/\\\/youtube.com\\\/maurobernal\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados &#183; devops Mauro Bernal","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/","og_locale":"es_ES","og_type":"article","og_title":"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados &#183; devops Mauro Bernal","og_description":"Gu\u00eda completa del Patr\u00f3n Options en .NET hasta .NET 10: diferencias entre IOptions, IOptionsSnapshot e IOptionsMonitor, cu\u00e1ndo usar cada uno, la trampa de Captive Dependency, y validaci\u00f3n moderna con ValidateOnStart y Source Generators. Con ejemplos reales y tabla comparativa.","og_url":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/","og_site_name":"devops Mauro Bernal","article_published_time":"2026-03-17T00:45:28+00:00","author":"Mauro Bernal","twitter_card":"summary_large_image","twitter_creator":"@_maurobernal","twitter_site":"@_maurobernal","twitter_misc":{"Escrito por":"Mauro Bernal","Tiempo de lectura":"6 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/#article","isPartOf":{"@id":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/"},"author":{"name":"Mauro Bernal","@id":"https:\/\/maurobernal.com.ar\/blog\/#\/schema\/person\/09c4dbdfb59b20e015c703fd19713283"},"headline":"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados","datePublished":"2026-03-17T00:45:28+00:00","mainEntityOfPage":{"@id":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/"},"wordCount":935,"commentCount":0,"publisher":{"@id":"https:\/\/maurobernal.com.ar\/blog\/#\/schema\/person\/09c4dbdfb59b20e015c703fd19713283"},"keywords":[".NET 10","BackgroundService","Configuracion","Dependency Injection","Fail Fast","Hot Reload","IOptions","IOptionsMonitor","IOptionsSnapshot","Options Pattern","OptionsValidator","POCO","Source Generators","ValidateOnStart"],"articleSection":["Blog","DotNet"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/","url":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/","name":"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados &#183; devops Mauro Bernal","isPartOf":{"@id":"https:\/\/maurobernal.com.ar\/blog\/#website"},"datePublished":"2026-03-17T00:45:28+00:00","breadcrumb":{"@id":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/maurobernal.com.ar\/blog\/patron-options-dotnet-ioptions-ioptionssnapshot-ioptionsmonitor\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Portada","item":"https:\/\/maurobernal.com.ar\/blog\/"},{"@type":"ListItem","position":2,"name":"El Patr\u00f3n Options en .NET: IOptions, IOptionsSnapshot e IOptionsMonitor Explicados"}]},{"@type":"WebSite","@id":"https:\/\/maurobernal.com.ar\/blog\/#website","url":"https:\/\/maurobernal.com.ar\/blog\/","name":"devops Mauro Bernal","description":"Cuando tu trabajo es hacer que las cosas funcionen bien...","publisher":{"@id":"https:\/\/maurobernal.com.ar\/blog\/#\/schema\/person\/09c4dbdfb59b20e015c703fd19713283"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/maurobernal.com.ar\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":["Person","Organization"],"@id":"https:\/\/maurobernal.com.ar\/blog\/#\/schema\/person\/09c4dbdfb59b20e015c703fd19713283","name":"Mauro Bernal","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/i0.wp.com\/maurobernal.com.ar\/blog\/wp-content\/uploads\/2023\/07\/logo-maurobernal.png?fit=1740%2C1740&ssl=1","url":"https:\/\/i0.wp.com\/maurobernal.com.ar\/blog\/wp-content\/uploads\/2023\/07\/logo-maurobernal.png?fit=1740%2C1740&ssl=1","contentUrl":"https:\/\/i0.wp.com\/maurobernal.com.ar\/blog\/wp-content\/uploads\/2023\/07\/logo-maurobernal.png?fit=1740%2C1740&ssl=1","width":1740,"height":1740,"caption":"Mauro Bernal"},"logo":{"@id":"https:\/\/i0.wp.com\/maurobernal.com.ar\/blog\/wp-content\/uploads\/2023\/07\/logo-maurobernal.png?fit=1740%2C1740&ssl=1"},"description":"Desarrollo de Sistemas en .Net, IT Callcenters, DBA de SQL Server, Mikrotik, Pentest y T\u00e9cnico consultor de Sistemas Bejerman","sameAs":["https:\/\/maurobernal.com.ar","https:\/\/x.com\/_maurobernal","https:\/\/youtube.com\/maurobernal"]}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/maurobernal.com.ar\/blog\/wp-json\/wp\/v2\/posts\/1299","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/maurobernal.com.ar\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/maurobernal.com.ar\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/maurobernal.com.ar\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/maurobernal.com.ar\/blog\/wp-json\/wp\/v2\/comments?post=1299"}],"version-history":[{"count":0,"href":"https:\/\/maurobernal.com.ar\/blog\/wp-json\/wp\/v2\/posts\/1299\/revisions"}],"wp:attachment":[{"href":"https:\/\/maurobernal.com.ar\/blog\/wp-json\/wp\/v2\/media?parent=1299"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/maurobernal.com.ar\/blog\/wp-json\/wp\/v2\/categories?post=1299"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/maurobernal.com.ar\/blog\/wp-json\/wp\/v2\/tags?post=1299"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}