[{"data":1,"prerenderedAt":6410},["ShallowReactive",2],{"navigation_docs":3,"-sdks-server-dotnet":244,"-sdks-server-dotnet-surround":6405},[4,51,78,229],{"title":5,"icon":6,"modifiedAt":7,"path":8,"stem":9,"children":10,"page":6},"Getting Started",false,"2026-04-30T19:15:33.000Z","\u002Fgetting-started","1.getting-started",[11,16,21,26,31,36,41,46],{"title":12,"path":13,"stem":14,"icon":15},"Quickstart","\u002Fgetting-started\u002Fquickstart","1.getting-started\u002F1.quickstart","i-lucide-fast-forward",{"title":17,"path":18,"stem":19,"icon":20},"Core Concepts","\u002Fgetting-started\u002Fcore-concepts","1.getting-started\u002F2.core-concepts","i-lucide-workflow",{"title":22,"path":23,"stem":24,"icon":25},"Configs Anatomy","\u002Fgetting-started\u002Fconfigs","1.getting-started\u002F3.configs","i-lucide-file-cog",{"title":27,"path":28,"stem":29,"icon":30},"Architecture","\u002Fgetting-started\u002Farchitecture","1.getting-started\u002F4.architecture","i-lucide-layers",{"title":32,"path":33,"stem":34,"icon":35},"JSON Schema Validation","\u002Fgetting-started\u002Fjson-schema-validation","1.getting-started\u002F5.json-schema-validation","i-lucide-braces",{"title":37,"path":38,"stem":39,"icon":40},"Testing Rules","\u002Fgetting-started\u002Ftesting-targeting-rules","1.getting-started\u002F6.testing-targeting-rules","i-lucide-flask-conical",{"title":42,"path":43,"stem":44,"icon":45},"Segments","\u002Fgetting-started\u002Fsegments","1.getting-started\u002F7.segments","i-lucide-squares-intersect",{"title":47,"path":48,"stem":49,"icon":50},"Pricing & Billing","\u002Fgetting-started\u002Fpricing-and-billing","1.getting-started\u002F8.pricing-and-billing","i-lucide-credit-card",{"title":52,"modifiedAt":53,"defaultOpen":54,"path":55,"stem":56,"children":57,"page":6},"Monitoring","2026-09-24T23:33:20.000Z",true,"\u002Fmonitoring","2.monitoring",[58,63,68,73],{"title":59,"path":60,"stem":61,"icon":62},"Activity","\u002Fmonitoring\u002Factivity","2.monitoring\u002F1.activity","i-lucide-activity",{"title":64,"path":65,"stem":66,"icon":67},"Lifecycle","\u002Fmonitoring\u002Flifecycle","2.monitoring\u002F2.lifecycle","i-lucide-recycle",{"title":69,"path":70,"stem":71,"icon":72},"Alerts","\u002Fmonitoring\u002Falerts","2.monitoring\u002F3.alerts","i-lucide-bell",{"title":74,"path":75,"stem":76,"icon":77},"Dynamic Detection","\u002Fmonitoring\u002Fdynamic-detection","2.monitoring\u002F4.dynamic-detection","i-lucide-hat-glasses",{"title":79,"modifiedAt":53,"defaultOpen":54,"path":80,"stem":81,"children":82,"page":6},"SDKs","\u002Fsdks","3.sdks",[83,88,109,134,150,181,224],{"title":84,"path":85,"stem":86,"icon":87},"Available SDKs","\u002Fsdks\u002Favailable-sdks","3.sdks\u002F1.available-sdks","i-lucide-list",{"title":89,"modifiedAt":53,"icon":90,"defaultOpen":6,"path":91,"stem":92,"children":93,"page":6},"Browser SDKs","i-lucide-monitor","\u002Fsdks\u002Fbrowser","3.sdks\u002F2.browser",[94,99,104],{"title":95,"path":96,"stem":97,"icon":98},"Javascript","\u002Fsdks\u002Fbrowser\u002Fjavascript","3.sdks\u002F2.browser\u002F1.javascript","cd-logos-javascript",{"title":100,"path":101,"stem":102,"icon":103},"React","\u002Fsdks\u002Fbrowser\u002Freact","3.sdks\u002F2.browser\u002F2.react","cd-logos-react-light",{"title":105,"path":106,"stem":107,"icon":108},"Vue","\u002Fsdks\u002Fbrowser\u002Fvue","3.sdks\u002F2.browser\u002F3.vue","cd-logos-vue",{"title":110,"modifiedAt":53,"icon":111,"defaultOpen":6,"path":112,"stem":113,"children":114,"page":6},"Mobile SDKs","i-lucide-smartphone","\u002Fsdks\u002Fmobile","3.sdks\u002F3.mobile",[115,119,124,129],{"title":116,"path":117,"stem":118,"icon":103},"React Native","\u002Fsdks\u002Fmobile\u002Freact-native","3.sdks\u002F3.mobile\u002F1.react-native",{"title":120,"path":121,"stem":122,"icon":123},"Flutter","\u002Fsdks\u002Fmobile\u002Fflutter","3.sdks\u002F3.mobile\u002F2.flutter","cd-logos-flutter",{"title":125,"path":126,"stem":127,"icon":128},"Swift","\u002Fsdks\u002Fmobile\u002Fswift","3.sdks\u002F3.mobile\u002F3.swift","cd-logos-swift",{"title":130,"path":131,"stem":132,"icon":133},"Android","\u002Fsdks\u002Fmobile\u002Fandroid","3.sdks\u002F3.mobile\u002F4.android","cd-logos-android",{"title":135,"modifiedAt":53,"icon":136,"defaultOpen":6,"path":137,"stem":138,"children":139,"page":6},"Meta-framework SDKs","i-lucide-monitor-smartphone","\u002Fsdks\u002Fmeta","3.sdks\u002F4.meta",[140,145],{"title":141,"path":142,"stem":143,"icon":144},"Next.js","\u002Fsdks\u002Fmeta\u002Fnextjs","3.sdks\u002F4.meta\u002F1.nextjs","cd-logos-nextjs",{"title":146,"path":147,"stem":148,"icon":149},"Nuxt","\u002Fsdks\u002Fmeta\u002Fnuxt","3.sdks\u002F4.meta\u002F2.nuxt","cd-logos-nuxt",{"title":151,"modifiedAt":53,"icon":152,"defaultOpen":6,"path":153,"stem":154,"children":155,"page":6},"Server SDKs","i-lucide-server","\u002Fsdks\u002Fserver","3.sdks\u002F5.server",[156,161,166,171,176],{"title":157,"path":158,"stem":159,"icon":160},"Node.js","\u002Fsdks\u002Fserver\u002Fnode-js","3.sdks\u002F5.server\u002F1.node-js","cd-logos-nodejs",{"title":162,"path":163,"stem":164,"icon":165},"Python","\u002Fsdks\u002Fserver\u002Fpython","3.sdks\u002F5.server\u002F2.python","cd-logos-python",{"title":167,"path":168,"stem":169,"icon":170},"Java","\u002Fsdks\u002Fserver\u002Fjava","3.sdks\u002F5.server\u002F3.java","cd-logos-java",{"title":172,"path":173,"stem":174,"icon":175},".NET","\u002Fsdks\u002Fserver\u002Fdotnet","3.sdks\u002F5.server\u002F4.dotnet","cd-logos-dotnet",{"title":177,"path":178,"stem":179,"icon":180},"Go","\u002Fsdks\u002Fserver\u002Fgo","3.sdks\u002F5.server\u002F5.go","cd-logos-go",{"title":182,"modifiedAt":53,"icon":183,"defaultOpen":6,"path":184,"stem":185,"children":186,"page":6},"OpenFeature Providers","cd-logos-openfeature","\u002Fsdks\u002Fopenfeature","3.sdks\u002F6.openfeature",[187,192,196,200,204,208,212,216,220],{"title":188,"path":189,"stem":190,"icon":183,"icons":191},"Web","\u002Fsdks\u002Fopenfeature\u002Fweb","3.sdks\u002F6.openfeature\u002F1.web",[183,98],{"title":125,"path":193,"stem":194,"icon":183,"icons":195},"\u002Fsdks\u002Fopenfeature\u002Fswift","3.sdks\u002F6.openfeature\u002F2.swift",[183,128],{"title":130,"path":197,"stem":198,"icon":183,"icons":199},"\u002Fsdks\u002Fopenfeature\u002Fandroid","3.sdks\u002F6.openfeature\u002F3.android",[183,133],{"title":120,"path":201,"stem":202,"icon":183,"icons":203},"\u002Fsdks\u002Fopenfeature\u002Fflutter","3.sdks\u002F6.openfeature\u002F4.flutter",[183,123],{"title":157,"path":205,"stem":206,"icon":183,"icons":207},"\u002Fsdks\u002Fopenfeature\u002Fnode-js","3.sdks\u002F6.openfeature\u002F5.node-js",[183,160],{"title":162,"path":209,"stem":210,"icon":183,"icons":211},"\u002Fsdks\u002Fopenfeature\u002Fpython","3.sdks\u002F6.openfeature\u002F6.python",[183,165],{"title":167,"path":213,"stem":214,"icon":183,"icons":215},"\u002Fsdks\u002Fopenfeature\u002Fjava","3.sdks\u002F6.openfeature\u002F7.java",[183,170],{"title":172,"path":217,"stem":218,"icon":183,"icons":219},"\u002Fsdks\u002Fopenfeature\u002Fdotnet","3.sdks\u002F6.openfeature\u002F8.dotnet",[183,175],{"title":177,"path":221,"stem":222,"icon":183,"icons":223},"\u002Fsdks\u002Fopenfeature\u002Fgo","3.sdks\u002F6.openfeature\u002F9.go",[183,180],{"title":225,"path":226,"stem":227,"icon":228},"Maven Repository","\u002Fsdks\u002Fmaven-repository","3.sdks\u002F7.maven-repository","i-lucide-package",{"title":230,"modifiedAt":53,"defaultOpen":54,"path":231,"stem":232,"children":233,"page":6},"Integrations","\u002Fintegrations","4.integrations",[234,239],{"title":235,"path":236,"stem":237,"icon":238},"Terraform","\u002Fintegrations\u002Fterraform","4.integrations\u002F1.terraform","cd-logos-terraform",{"title":240,"path":241,"stem":242,"icon":243},"MCP","\u002Fintegrations\u002Fmcp","4.integrations\u002F2.mcp","cd-logos-mcp",{"id":245,"title":246,"body":247,"description":6397,"extension":6398,"links":6399,"meta":6400,"navigation":6402,"path":173,"seo":6403,"stem":174,"__hash__":6404},"docs\u002F3.sdks\u002F5.server\u002F4.dotnet.md",".NET Server SDK",{"type":248,"value":249,"toc":6361},"minimark",[250,254,260,265,269,281,284,297,301,309,419,423,437,556,559,563,576,598,603,617,632,639,645,762,768,783,835,842,921,926,929,1030,1159,1164,1167,1170,1173,1207,1293,1297,1307,1428,1431,1612,1616,1626,1904,1907,1949,1952,1997,2001,2013,2178,2194,2200,2204,2207,2214,2217,2364,2369,2522,2527,2579,2741,2745,2759,2765,2912,2921,2925,2928,2933,2942,2948,2951,2957,2967,2970,2976,2979,2985,2988,2992,2995,3008,3011,3209,3221,3224,3227,3232,3238,3247,3251,3258,3329,3335,3339,3420,3423,3503,3506,3539,3560,3567,3573,3579,3624,3630,3671,3678,3696,3700,3706,3799,3806,4004,4007,4032,4035,4039,4042,4051,4093,4096,4221,4225,4234,4390,4400,4636,4648,4656,4660,4729,4744,4747,4852,4871,4874,4886,4892,4912,5137,5159,5163,5172,5192,5490,5534,5555,5570,5888,5892,5955,5972,5976,6098,6104,6267,6270,6288,6292,6357],[251,252],"div",{"hidden":54,"dataTitleIcon":253},"dotnet",[255,256],"external-badges",{"package-url":257,"registry":258,"repo":259},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FConfigDirector.ServerSdk","nuget","dotnet-sdks",[261,262,264],"h2",{"id":263},"introduction","Introduction",[266,267,268],"p",{},"The .NET Server SDK is a server-side SDK that evaluates configs and their targeting rules. Upon initialization, it retrieves configs and targeting rules from ConfigDirector services. From that point on, it evaluates configs locally for any user context, and receives updates via server sent events (SSE) when configs are updated on the dashboard or via the admin API.",[266,270,271,272,276,277,280],{},"The SDK targets ",[273,274,275],"code",{},"net8.0"," and ",[273,278,279],{},"netstandard2.0",", so it runs on .NET 8 and later as well as on .NET Framework 4.6.2 and later.",[266,282,283],{},"The client is thread safe. Create one instance when your application starts, share it for the lifetime of the process, and dispose it on shutdown. Evaluations read config state the client already holds in memory, so they make no network calls on the request path.",[266,285,286,287,290,291,296],{},"In an ASP.NET Core application, the companion ",[273,288,289],{},"ConfigDirector.ServerSdk.AspNetCore"," package does that wiring for you: registration, configuration binding, startup initialization, and disposal. Everything on this page applies either way, see ",[292,293,295],"a",{"href":294},"#aspnet-core","ASP.NET Core"," further below.",[261,298,300],{"id":299},"installation","Installation",[266,302,303,304],{},"The SDK can be installed from NuGet: ",[292,305,257],{"href":257,"rel":306,"target":308},[307],"noopener","_blank",[310,311,312,348],"code-group",{},[313,314,320],"pre",{"className":315,"code":316,"filename":317,"language":318,"meta":319,"style":319},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","dotnet add package ConfigDirector.ServerSdk --version 1.7.1\n",".NET CLI","bash","",[273,321,322],{"__ignoreMap":319},[323,324,327,330,334,337,340,344],"span",{"class":325,"line":326},"line",1,[323,328,253],{"class":329},"sbgvK",[323,331,333],{"class":332},"s_sjI"," add",[323,335,336],{"class":332}," package",[323,338,339],{"class":332}," ConfigDirector.ServerSdk",[323,341,343],{"class":342},"stzsN"," --version",[323,345,347],{"class":346},"srdBf"," 1.7.1\n",[313,349,354],{"className":350,"code":351,"filename":352,"language":353,"meta":319,"style":319},"language-xml shiki shiki-themes material-theme-lighter github-light github-dark","\u003CItemGroup>\n  \u003CPackageReference Include=\"ConfigDirector.ServerSdk\" Version=\"1.7.1\" \u002F>\n\u003C\u002FItemGroup>\n",".csproj","xml",[273,355,356,369,409],{"__ignoreMap":319},[323,357,358,362,366],{"class":325,"line":326},[323,359,361],{"class":360},"sP7_E","\u003C",[323,363,365],{"class":364},"sQzsp","ItemGroup",[323,367,368],{"class":360},">\n",[323,370,372,375,378,382,385,389,392,394,397,399,401,404,406],{"class":325,"line":371},2,[323,373,374],{"class":360},"  \u003C",[323,376,377],{"class":364},"PackageReference",[323,379,381],{"class":380},"s9AJx"," Include",[323,383,384],{"class":360},"=",[323,386,388],{"class":387},"sjJ54","\"",[323,390,391],{"class":332},"ConfigDirector.ServerSdk",[323,393,388],{"class":387},[323,395,396],{"class":380}," Version",[323,398,384],{"class":360},[323,400,388],{"class":387},[323,402,403],{"class":332},"1.7.1",[323,405,388],{"class":387},[323,407,408],{"class":360}," \u002F>\n",[323,410,412,415,417],{"class":325,"line":411},3,[323,413,414],{"class":360},"\u003C\u002F",[323,416,365],{"class":364},[323,418,368],{"class":360},[261,420,422],{"id":421},"configure-and-initialize-the-client","Configure and initialize the client",[424,425,426,434],"ol",{},[427,428,429,430,433],"li",{},"Create an instance of the client providing your server SDK key. You can retrieve a server SDK key for each environment under ",[273,431,432],{},"SDK keys"," in the dashboard's navigation panel.",[427,435,436],{},"Initialize the client to initiate its connection lifecycle.",[313,438,443],{"className":439,"code":440,"filename":441,"language":442,"meta":319,"style":319},"language-csharp shiki shiki-themes material-theme-lighter github-light github-dark","using ConfigDirector;\n\n\u002F\u002F IMPORTANT: Do not commit the server SDK key to your source code, it is a secret value.\n\u002F\u002F Building the client makes no network calls.\nawait using var client = new ConfigDirectorClient(\"YOUR-SERVER-SDK-KEY\");\n\n\u002F\u002F Waits until the client is initialized or it times out.\n\u002F\u002F If initialization times out, the client will continue attempting to\n\u002F\u002F initialize in the background.\nawait client.InitializeAsync();\n","ConfigDirectorSetup.cs","csharp",[273,444,445,458,463,469,475,515,520,526,532,538],{"__ignoreMap":319},[323,446,447,451,455],{"class":325,"line":326},[323,448,450],{"class":449},"sw1J6","using",[323,452,454],{"class":453},"sfCm-"," ConfigDirector",[323,456,457],{"class":360},";\n",[323,459,460],{"class":325,"line":371},[323,461,462],{"emptyLinePlaceholder":54},"\n",[323,464,465],{"class":325,"line":411},[323,466,468],{"class":467},"sutJx","\u002F\u002F IMPORTANT: Do not commit the server SDK key to your source code, it is a secret value.\n",[323,470,472],{"class":325,"line":471},4,[323,473,474],{"class":467},"\u002F\u002F Building the client makes no network calls.\n",[323,476,478,482,486,490,493,496,499,502,505,507,510,512],{"class":325,"line":477},5,[323,479,481],{"class":480},"smGrS","await",[323,483,485],{"class":484},"sVHd0"," using",[323,487,489],{"class":488},"sG8yY"," var",[323,491,492],{"class":329}," client",[323,494,495],{"class":480}," =",[323,497,498],{"class":480}," new",[323,500,501],{"class":329}," ConfigDirectorClient",[323,503,504],{"class":360},"(",[323,506,388],{"class":387},[323,508,509],{"class":332},"YOUR-SERVER-SDK-KEY",[323,511,388],{"class":387},[323,513,514],{"class":360},");\n",[323,516,518],{"class":325,"line":517},6,[323,519,462],{"emptyLinePlaceholder":54},[323,521,523],{"class":325,"line":522},7,[323,524,525],{"class":467},"\u002F\u002F Waits until the client is initialized or it times out.\n",[323,527,529],{"class":325,"line":528},8,[323,530,531],{"class":467},"\u002F\u002F If initialization times out, the client will continue attempting to\n",[323,533,535],{"class":325,"line":534},9,[323,536,537],{"class":467},"\u002F\u002F initialize in the background.\n",[323,539,541,543,546,549,553],{"class":325,"line":540},10,[323,542,481],{"class":480},[323,544,492],{"class":545},"su5hD",[323,547,548],{"class":360},".",[323,550,552],{"class":551},"sGLFI","InitializeAsync",[323,554,555],{"class":360},"();\n",[266,557,558],{},"The client is thread safe. Create one at startup, share it for the lifetime of the process, and dispose it on shutdown.",[560,561,562],"warning",{},"Server SDK keys are secret values. Do not commit them to your source code repository. Provide them at runtime via environment variables instead.",[266,564,565,567,568,571,572,575],{},[273,566,552],{}," completes when the initial config state arrives or the configured timeout elapses, and it never throws on a connection failure. Check ",[273,569,570],{},"IsReady"," to find out whether config state actually arrived. It also accepts a ",[273,573,574],{},"CancellationToken"," to abandon the wait:",[313,577,579],{"className":439,"code":578,"filename":441,"language":442,"meta":319,"style":319},"await client.InitializeAsync(cancellationToken);\n",[273,580,581],{"__ignoreMap":319},[323,582,583,585,587,589,591,593,596],{"class":325,"line":326},[323,584,481],{"class":480},[323,586,492],{"class":545},[323,588,548],{"class":360},[323,590,552],{"class":551},[323,592,504],{"class":360},[323,594,595],{"class":545},"cancellationToken",[323,597,514],{"class":360},[599,600,602],"h3",{"id":601},"additional-configuration-options","Additional configuration options",[266,604,605,606,609,610,276,613,616],{},"Options are supplied through a ",[273,607,608],{},"ConfigDirectorClientOptions"," passed to the constructor. ",[273,611,612],{},"Connection",[273,614,615],{},"Telemetry"," are get-only, so they are populated with a nested object initializer. Options are read once when the client is built; changing them afterwards has no effect.",[266,618,619,620,623,624,627,628,631],{},"Each setting is validated as it is assigned, so an unusable value throws an ",[273,621,622],{},"ArgumentOutOfRangeException"," (or an ",[273,625,626],{},"ArgumentException"," for a relative ",[273,629,630],{},"Url",") at the line that wrote it rather than as a client that quietly never updates.",[633,634,636],"h4",{"id":635},"metadata",[273,637,638],{},"Metadata",[266,640,641,642,644],{},"The ",[273,643,638],{}," option allows you to provide your application's name and version. These values can be used in targeting rules conditionals. For example, if a certain feature should only be enabled starting with a certain version of your application.",[313,646,648],{"className":439,"code":647,"filename":441,"language":442,"meta":319,"style":319},"using ConfigDirector;\n\nvar client = new ConfigDirectorClient(\"YOUR-SERVER-SDK-KEY\", new ConfigDirectorClientOptions\n{\n    Metadata = new Metadata { AppName = \"YOUR-APP-NAME\", AppVersion = \"1.0.2\" },\n});\n\nawait client.InitializeAsync();\n",[273,649,650,658,662,691,696,741,746,750],{"__ignoreMap":319},[323,651,652,654,656],{"class":325,"line":326},[323,653,450],{"class":449},[323,655,454],{"class":453},[323,657,457],{"class":360},[323,659,660],{"class":325,"line":371},[323,661,462],{"emptyLinePlaceholder":54},[323,663,664,667,669,671,673,675,677,679,681,683,686,688],{"class":325,"line":411},[323,665,666],{"class":488},"var",[323,668,492],{"class":329},[323,670,495],{"class":480},[323,672,498],{"class":480},[323,674,501],{"class":329},[323,676,504],{"class":360},[323,678,388],{"class":387},[323,680,509],{"class":332},[323,682,388],{"class":387},[323,684,685],{"class":360},",",[323,687,498],{"class":480},[323,689,690],{"class":329}," ConfigDirectorClientOptions\n",[323,692,693],{"class":325,"line":471},[323,694,695],{"class":360},"{\n",[323,697,698,701,703,705,708,711,714,716,719,722,724,726,729,731,733,736,738],{"class":325,"line":477},[323,699,700],{"class":545},"    Metadata ",[323,702,384],{"class":480},[323,704,498],{"class":480},[323,706,707],{"class":329}," Metadata",[323,709,710],{"class":360}," {",[323,712,713],{"class":545}," AppName ",[323,715,384],{"class":480},[323,717,718],{"class":387}," \"",[323,720,721],{"class":332},"YOUR-APP-NAME",[323,723,388],{"class":387},[323,725,685],{"class":360},[323,727,728],{"class":545}," AppVersion ",[323,730,384],{"class":480},[323,732,718],{"class":387},[323,734,735],{"class":332},"1.0.2",[323,737,388],{"class":387},[323,739,740],{"class":360}," },\n",[323,742,743],{"class":325,"line":517},[323,744,745],{"class":360},"});\n",[323,747,748],{"class":325,"line":522},[323,749,462],{"emptyLinePlaceholder":54},[323,751,752,754,756,758,760],{"class":325,"line":528},[323,753,481],{"class":480},[323,755,492],{"class":545},[323,757,548],{"class":360},[323,759,552],{"class":551},[323,761,555],{"class":360},[633,763,765],{"id":764},"loggerfactory",[273,766,767],{},"LoggerFactory",[266,769,770,771,774,775,778,779,782],{},"The SDK logs through ",[273,772,773],{},"Microsoft.Extensions.Logging",". It defaults to ",[273,776,777],{},"NullLoggerFactory",", which discards everything, so pass your application's own ",[273,780,781],{},"ILoggerFactory"," to route the SDK's output through your logging pipeline:",[313,784,786],{"className":439,"code":785,"filename":441,"language":442,"meta":319,"style":319},"var client = new ConfigDirectorClient(\"YOUR-SERVER-SDK-KEY\", new ConfigDirectorClientOptions\n{\n    LoggerFactory = loggerFactory,\n});\n",[273,787,788,814,818,831],{"__ignoreMap":319},[323,789,790,792,794,796,798,800,802,804,806,808,810,812],{"class":325,"line":326},[323,791,666],{"class":488},[323,793,492],{"class":329},[323,795,495],{"class":480},[323,797,498],{"class":480},[323,799,501],{"class":329},[323,801,504],{"class":360},[323,803,388],{"class":387},[323,805,509],{"class":332},[323,807,388],{"class":387},[323,809,685],{"class":360},[323,811,498],{"class":480},[323,813,690],{"class":329},[323,815,816],{"class":325,"line":371},[323,817,695],{"class":360},[323,819,820,823,825,828],{"class":325,"line":411},[323,821,822],{"class":545},"    LoggerFactory ",[323,824,384],{"class":480},[323,826,827],{"class":545}," loggerFactory",[323,829,830],{"class":360},",\n",[323,832,833],{"class":325,"line":471},[323,834,745],{"class":360},[266,836,837,838,841],{},"Categories are namespaced under ",[273,839,840],{},"ConfigDirector",", so levels, formatting, and destinations are controlled through your usual logging configuration:",[313,843,848],{"className":844,"code":845,"filename":846,"language":847,"meta":319,"style":319},"language-json shiki shiki-themes material-theme-lighter github-light github-dark","{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"ConfigDirector\": \"Debug\"\n    }\n  }\n}\n","appsettings.json","json",[273,849,850,854,872,887,906,911,916],{"__ignoreMap":319},[323,851,852],{"class":325,"line":326},[323,853,695],{"class":360},[323,855,856,860,864,866,869],{"class":325,"line":371},[323,857,859],{"class":858},"s39Yj","  \"",[323,861,863],{"class":862},"sseR_","Logging",[323,865,388],{"class":858},[323,867,868],{"class":360},":",[323,870,871],{"class":360}," {\n",[323,873,874,877,881,883,885],{"class":325,"line":411},[323,875,876],{"class":858},"    \"",[323,878,880],{"class":879},"sZMiF","LogLevel",[323,882,388],{"class":858},[323,884,868],{"class":360},[323,886,871],{"class":360},[323,888,889,892,894,896,898,900,903],{"class":325,"line":471},[323,890,891],{"class":858},"      \"",[323,893,840],{"class":346},[323,895,388],{"class":858},[323,897,868],{"class":360},[323,899,718],{"class":387},[323,901,902],{"class":332},"Debug",[323,904,905],{"class":387},"\"\n",[323,907,908],{"class":325,"line":477},[323,909,910],{"class":360},"    }\n",[323,912,913],{"class":325,"line":517},[323,914,915],{"class":360},"  }\n",[323,917,918],{"class":325,"line":522},[323,919,920],{"class":360},"}\n",[633,922,924],{"id":923},"connection",[273,925,612],{},[266,927,928],{},"The connection options have the following optional values:",[930,931,932,963,993,1015],"ul",{},[427,933,934,937],{},[273,935,936],{},"Mode",[930,938,939,958],{},[427,940,941,942,945,946,949,950,953,954,957],{},"The connection mode, which can be ",[273,943,944],{},"ConnectionMode.Streaming"," or ",[273,947,948],{},"ConnectionMode.Polling",". It is recommended to use the default of ",[273,951,952],{},"Streaming"," unless you have a specific need to use ",[273,955,956],{},"Polling"," instead.",[427,959,960,961],{},"Defaults to ",[273,962,944],{},[427,964,965,968],{},[273,966,967],{},"PollingInterval",[930,969,970,987],{},[427,971,972,973,975,976,979,980,982,983,548],{},"Only used in ",[273,974,956],{}," mode. The interval to poll ConfigDirector services for updates. A value below the minimum of ",[273,977,978],{},"1"," minute is raised to ",[273,981,978],{}," minute and a warning is logged, including when it is bound from configuration. See ",[292,984,986],{"href":985},"\u002Fgetting-started\u002Farchitecture#polling-intervals","Polling intervals",[427,988,960,989,992],{},[273,990,991],{},"5"," minutes",[427,994,995,998],{},[273,996,997],{},"Timeout",[930,999,1000,1009],{},[427,1001,1002,1003,1005,1006,1008],{},"The timeout to be used in initialization, and the limit on any single request to ConfigDirector services. This is how long ",[273,1004,552],{}," will wait for data from ConfigDirector services. If the timeout is reached, ",[273,1007,552],{}," will return but the client will still be in an unready status and returning default values. While streaming, the client will continue to attempt to connect and retrieve config values in the background.",[427,1010,960,1011,1014],{},[273,1012,1013],{},"3"," seconds",[427,1016,1017,1019],{},[273,1018,630],{},[930,1020,1021,1027],{},[427,1022,1023,1024,548],{},"The base URL used to connect to ConfigDirector services. Must be an absolute ",[273,1025,1026],{},"Uri",[427,1028,1029],{},"This should only be provided if your environment requires you to configure a proxy server in order to connect to ConfigDirector services",[313,1031,1033],{"className":439,"code":1032,"filename":441,"language":442,"meta":319,"style":319},"using ConfigDirector;\n\nvar client = new ConfigDirectorClient(\"YOUR-SERVER-SDK-KEY\", new ConfigDirectorClientOptions\n{\n    Connection =\n    {\n        Mode = ConnectionMode.Polling,\n        PollingInterval = TimeSpan.FromMinutes(10),\n        Timeout = TimeSpan.FromSeconds(5),\n    },\n});\n",[273,1034,1035,1043,1047,1073,1077,1085,1090,1106,1129,1149,1154],{"__ignoreMap":319},[323,1036,1037,1039,1041],{"class":325,"line":326},[323,1038,450],{"class":449},[323,1040,454],{"class":453},[323,1042,457],{"class":360},[323,1044,1045],{"class":325,"line":371},[323,1046,462],{"emptyLinePlaceholder":54},[323,1048,1049,1051,1053,1055,1057,1059,1061,1063,1065,1067,1069,1071],{"class":325,"line":411},[323,1050,666],{"class":488},[323,1052,492],{"class":329},[323,1054,495],{"class":480},[323,1056,498],{"class":480},[323,1058,501],{"class":329},[323,1060,504],{"class":360},[323,1062,388],{"class":387},[323,1064,509],{"class":332},[323,1066,388],{"class":387},[323,1068,685],{"class":360},[323,1070,498],{"class":480},[323,1072,690],{"class":329},[323,1074,1075],{"class":325,"line":471},[323,1076,695],{"class":360},[323,1078,1079,1082],{"class":325,"line":477},[323,1080,1081],{"class":545},"    Connection ",[323,1083,1084],{"class":480},"=\n",[323,1086,1087],{"class":325,"line":517},[323,1088,1089],{"class":360},"    {\n",[323,1091,1092,1095,1097,1100,1102,1104],{"class":325,"line":522},[323,1093,1094],{"class":545},"        Mode ",[323,1096,384],{"class":480},[323,1098,1099],{"class":545}," ConnectionMode",[323,1101,548],{"class":360},[323,1103,956],{"class":545},[323,1105,830],{"class":360},[323,1107,1108,1111,1113,1116,1118,1121,1123,1126],{"class":325,"line":528},[323,1109,1110],{"class":545},"        PollingInterval ",[323,1112,384],{"class":480},[323,1114,1115],{"class":545}," TimeSpan",[323,1117,548],{"class":360},[323,1119,1120],{"class":551},"FromMinutes",[323,1122,504],{"class":360},[323,1124,1125],{"class":346},"10",[323,1127,1128],{"class":360},"),\n",[323,1130,1131,1134,1136,1138,1140,1143,1145,1147],{"class":325,"line":534},[323,1132,1133],{"class":545},"        Timeout ",[323,1135,384],{"class":480},[323,1137,1115],{"class":545},[323,1139,548],{"class":360},[323,1141,1142],{"class":551},"FromSeconds",[323,1144,504],{"class":360},[323,1146,991],{"class":346},[323,1148,1128],{"class":360},[323,1150,1151],{"class":325,"line":540},[323,1152,1153],{"class":360},"    },\n",[323,1155,1157],{"class":325,"line":1156},11,[323,1158,745],{"class":360},[633,1160,1162],{"id":1161},"telemetry",[273,1163,615],{},[266,1165,1166],{},"Telemetry tuning. It is unlikely these settings need to be adjusted. However, in cases where your application has a large number of evaluations per second, you can adjust these settings to tune the memory footprint and frequency of telemetry requests.",[266,1168,1169],{},"Keep in mind that ConfigDirector relies on these telemetry events to provide insights and features related to the configs being used.",[266,1171,1172],{},"The telemetry options have the following optional values:",[930,1174,1175,1191],{},[427,1176,1177,1180],{},[273,1178,1179],{},"EventQueueLimit",[930,1181,1182,1185,1188],{},[427,1183,1184],{},"The size limit of telemetry event queues. If the size limit is reached before the events are flushed to the network, older events will be dropped.",[427,1186,1187],{},"ConfigDirector keeps a count of dropped events. If the number of dropped events is higher than 50% of the total events, ConfigDirector will issue an alert in the dashboard.",[427,1189,1190],{},"A number between 100 and 100,000. Defaults to 5,000.",[427,1192,1193,1196],{},[273,1194,1195],{},"FlushInterval",[930,1197,1198,1201,1204],{},[427,1199,1200],{},"How often events are flushed and sent over the network.",[427,1202,1203],{},"Decrease this number if your application consistently captures a large number of events in short periods of time in order to reduce memory footprint from a large event queue.",[427,1205,1206],{},"Defaults to 30 seconds.",[313,1208,1210],{"className":439,"code":1209,"filename":441,"language":442,"meta":319,"style":319},"var client = new ConfigDirectorClient(\"YOUR-SERVER-SDK-KEY\", new ConfigDirectorClientOptions\n{\n    Telemetry =\n    {\n        EventQueueLimit = 10_000,\n        FlushInterval = TimeSpan.FromSeconds(15),\n    },\n});\n",[273,1211,1212,1238,1242,1249,1253,1265,1285,1289],{"__ignoreMap":319},[323,1213,1214,1216,1218,1220,1222,1224,1226,1228,1230,1232,1234,1236],{"class":325,"line":326},[323,1215,666],{"class":488},[323,1217,492],{"class":329},[323,1219,495],{"class":480},[323,1221,498],{"class":480},[323,1223,501],{"class":329},[323,1225,504],{"class":360},[323,1227,388],{"class":387},[323,1229,509],{"class":332},[323,1231,388],{"class":387},[323,1233,685],{"class":360},[323,1235,498],{"class":480},[323,1237,690],{"class":329},[323,1239,1240],{"class":325,"line":371},[323,1241,695],{"class":360},[323,1243,1244,1247],{"class":325,"line":411},[323,1245,1246],{"class":545},"    Telemetry ",[323,1248,1084],{"class":480},[323,1250,1251],{"class":325,"line":471},[323,1252,1089],{"class":360},[323,1254,1255,1258,1260,1263],{"class":325,"line":477},[323,1256,1257],{"class":545},"        EventQueueLimit ",[323,1259,384],{"class":480},[323,1261,1262],{"class":346}," 10_000",[323,1264,830],{"class":360},[323,1266,1267,1270,1272,1274,1276,1278,1280,1283],{"class":325,"line":517},[323,1268,1269],{"class":545},"        FlushInterval ",[323,1271,384],{"class":480},[323,1273,1115],{"class":545},[323,1275,548],{"class":360},[323,1277,1142],{"class":551},[323,1279,504],{"class":360},[323,1281,1282],{"class":346},"15",[323,1284,1128],{"class":360},[323,1286,1287],{"class":325,"line":522},[323,1288,1153],{"class":360},[323,1290,1291],{"class":325,"line":528},[323,1292,745],{"class":360},[599,1294,1296],{"id":1295},"hooks","Hooks",[266,1298,1299,1300,1303,1304,868],{},"Hooks are .NET events you can subscribe to in order to be notified of some key actions from the client. Subscribe with ",[273,1301,1302],{},"+="," and unsubscribe with ",[273,1305,1306],{},"-=",[313,1308,1310],{"className":439,"code":1309,"filename":441,"language":442,"meta":319,"style":319},"void OnConfigsUpdated(object? sender, ConfigsUpdatedEventArgs e) =>\n    Console.WriteLine(string.Join(\", \", e.Keys));\n\nclient.ConfigsUpdated += OnConfigsUpdated;\n\nclient.ConfigsUpdated -= OnConfigsUpdated; \u002F\u002F Cancels the registration\n",[273,1311,1312,1345,1386,1390,1406,1410],{"__ignoreMap":319},[323,1313,1314,1317,1320,1322,1325,1328,1331,1333,1336,1339,1342],{"class":325,"line":326},[323,1315,1316],{"class":480},"void",[323,1318,1319],{"class":551}," OnConfigsUpdated",[323,1321,504],{"class":360},[323,1323,1324],{"class":480},"object",[323,1326,1327],{"class":360},"?",[323,1329,1330],{"class":329}," sender",[323,1332,685],{"class":360},[323,1334,1335],{"class":329}," ConfigsUpdatedEventArgs",[323,1337,1338],{"class":329}," e",[323,1340,1341],{"class":360},")",[323,1343,1344],{"class":480}," =>\n",[323,1346,1347,1350,1352,1355,1357,1360,1362,1365,1367,1369,1372,1374,1376,1378,1380,1383],{"class":325,"line":371},[323,1348,1349],{"class":545},"    Console",[323,1351,548],{"class":360},[323,1353,1354],{"class":551},"WriteLine",[323,1356,504],{"class":360},[323,1358,1359],{"class":480},"string",[323,1361,548],{"class":360},[323,1363,1364],{"class":551},"Join",[323,1366,504],{"class":360},[323,1368,388],{"class":387},[323,1370,1371],{"class":332},", ",[323,1373,388],{"class":387},[323,1375,685],{"class":360},[323,1377,1338],{"class":545},[323,1379,548],{"class":360},[323,1381,1382],{"class":545},"Keys",[323,1384,1385],{"class":360},"));\n",[323,1387,1388],{"class":325,"line":411},[323,1389,462],{"emptyLinePlaceholder":54},[323,1391,1392,1395,1397,1400,1402,1404],{"class":325,"line":471},[323,1393,1394],{"class":545},"client",[323,1396,548],{"class":360},[323,1398,1399],{"class":545},"ConfigsUpdated ",[323,1401,1302],{"class":480},[323,1403,1319],{"class":545},[323,1405,457],{"class":360},[323,1407,1408],{"class":325,"line":477},[323,1409,462],{"emptyLinePlaceholder":54},[323,1411,1412,1414,1416,1418,1420,1422,1425],{"class":325,"line":517},[323,1413,1394],{"class":545},[323,1415,548],{"class":360},[323,1417,1399],{"class":545},[323,1419,1306],{"class":480},[323,1421,1319],{"class":545},[323,1423,1424],{"class":360},";",[323,1426,1427],{"class":467}," \u002F\u002F Cancels the registration\n",[266,1429,1430],{},"The following hooks are available:",[930,1432,1433,1448,1474],{},[427,1434,1435,1440],{},[273,1436,1439],{"className":1437},[1438],"font-semibold","ClientReady: ClientReadyEventArgs",[930,1441,1442],{},[427,1443,1444,1445,1447],{},"Emitted when the client is initialized. When this event is emitted it means the client has received a payload from the ConfigDirector servers and is ready to evaluate configs. It is emitted once, and a handler registered after that point is never called — check ",[273,1446,570],{}," for that.",[427,1449,1450,1454],{},[273,1451,1453],{"className":1452},[1438],"ConfigsUpdated: ConfigsUpdatedEventArgs",[930,1455,1456,1459,1465,1471],{},[427,1457,1458],{},"Emitted when a payload is received from the ConfigDirector servers with config data. It is emitted during initialization when an entire config payload is received. After initialization, it is emitted when updates are pushed from the server (or discovered via polling if that connection mode is used).",[427,1460,1461,1464],{},[273,1462,1463],{},"Keys: IReadOnlyList\u003Cstring>"," - The config keys that were included in the payload from the server, and the keys of configs whose targeting rules use a segment the payload included, sorted.",[427,1466,1467,1470],{},[273,1468,1469],{},"RemovedKeys: IReadOnlyList\u003Cstring>"," - The keys of configs the payload removed, sorted. A config is removed when a full payload no longer includes it. Empty when nothing was removed.",[427,1472,1473],{},"Handlers run on the thread the update arrived on, so one that blocks delays later updates.",[427,1475,1476,1480],{},[273,1477,1479],{"className":1478},[1438],"ConfigEvaluated: ConfigEvaluatedEventArgs",[930,1481,1482,1488,1609],{},[427,1483,1484,1485,548],{},"Emitted whenever a config is evaluated. This includes calls to the getters and evaluations delivered to watchers via ",[273,1486,1487],{},"Watch",[427,1489,1490,1493,1494,1497,1498],{},[273,1491,1492],{},"Evaluation: ConfigEvaluation"," - A ",[273,1495,1496],{},"ConfigEvaluation"," record containing the details of the evaluation:\n",[930,1499,1500,1506,1515,1529,1535,1600],{},[427,1501,1502,1505],{},[273,1503,1504],{},"Key: string"," - The config key that was evaluated",[427,1507,1508,1511,1512,1514],{},[273,1509,1510],{},"Value: object"," - The value the config evaluated to, in the type the caller's default asked for. It can be the default value provided to the getter or to ",[273,1513,1487],{},". For example, if the config was evaluated before the client was initialized.",[427,1516,1517,1520,1521,1524,1525,1528],{},[273,1518,1519],{},"ValueId: string?"," - The value ID, which is a stable hash of the value that can be used for analytics or other third parties rather than sending the ",[273,1522,1523],{},"Value",". This can be useful for large values, like a JSON config, or to avoid disclosing the values themselves to third parties. It is ",[273,1526,1527],{},"null"," when the evaluation fell back to the default value.",[427,1530,1531,1534],{},[273,1532,1533],{},"IsDefault: bool"," - Whether or not the evaluation fell back to the default value provided in code.",[427,1536,1537,1540,1541,1544,1545,1548,1549],{},[273,1538,1539],{},"Reason: EvaluationReason"," - The reason for the evaluation resolution. In the case the config successfully evaluated based on server-provided targeting rules, it will be ",[273,1542,1543],{},"FoundMatch",". If the evaluation had to fall back to the default value, the ",[273,1546,1547],{},"Reason"," will encode why the fallback was required:\n",[930,1550,1551,1557,1563,1569,1582,1588,1594],{},[427,1552,1553,1556],{},[273,1554,1555],{},"ClientNotReady"," - The evaluation happened before the client finished initialization",[427,1558,1559,1562],{},[273,1560,1561],{},"ConfigStateMissing"," - The requested config key was not present in the payload received from the server. This could be due to an incorrect config key, or a config that was not enabled to be available to client SDKs.",[427,1564,1565,1568],{},[273,1566,1567],{},"InvalidNumber"," - The config was requested as a number but the value received from the server could not be read as that number type.",[427,1570,1571,1574,1575,1578,1579,548],{},[273,1572,1573],{},"InvalidBoolean"," - The config was requested as a boolean but the value received from the server was neither ",[273,1576,1577],{},"true"," nor ",[273,1580,1581],{},"false",[427,1583,1584,1587],{},[273,1585,1586],{},"InvalidJson"," - The config was requested as JSON but the value received from the server could not be read as the JSON shape asked for.",[427,1589,1590,1593],{},[273,1591,1592],{},"TypeMismatch"," - The config was requested with a data type that did not match the type of the config and no reasonable type conversion was possible.",[427,1595,1596,1599],{},[273,1597,1598],{},"ValueMissing"," - The config key was present in the payload received from the server, but it carried no value.",[427,1601,1602,1605,1606,1608],{},[273,1603,1604],{},"Context: Context?"," - The user context that was provided to the evaluation function, or ",[273,1607,1527],{}," if no context was provided.",[427,1610,1611],{},"Handlers run on the calling thread, so one that blocks delays the getter that triggered it.",[261,1613,1615],{"id":1614},"retrieve-config-values","Retrieve config values",[266,1617,1618,1619,1622,1623,1625],{},"Retrieve config values via the typed ",[273,1620,1621],{},"GetValue"," overloads, and subscribe to updates via ",[273,1624,1487],{},". The first argument is the config key and the second is the default value, which is returned if the config is not available or cannot be read as the given type. The type of the default value decides the type the config is read as:",[313,1627,1630],{"className":439,"code":1628,"filename":1629,"language":442,"meta":319,"style":319},"using System.Text.Json;\n\n\u002F\u002F Retrieve config values\nvar retries = client.GetValue(\"max-retries\", 3);\nvar theme = client.GetValue(\"theme\", \"light\");\nvar newCheckout = client.GetValue(\"new-checkout\", false);\nvar limits = client.GetValue(\"rate-limits\", default(JsonElement)); \u002F\u002F JSON config\n\n\u002F\u002F Watch for config updates\nvar subscription = client.Watch(\n    \"new-checkout\",\n    false,\n    value => Console.WriteLine($\"new-checkout is now {value}\"));\n\n\u002F\u002F Dispose the subscription when it is no longer needed\nsubscription.Dispose();\n","Program.cs",[273,1631,1632,1651,1655,1660,1691,1726,1758,1798,1802,1807,1825,1835,1843,1880,1885,1891],{"__ignoreMap":319},[323,1633,1634,1636,1639,1641,1644,1646,1649],{"class":325,"line":326},[323,1635,450],{"class":449},[323,1637,1638],{"class":453}," System",[323,1640,548],{"class":360},[323,1642,1643],{"class":453},"Text",[323,1645,548],{"class":360},[323,1647,1648],{"class":453},"Json",[323,1650,457],{"class":360},[323,1652,1653],{"class":325,"line":371},[323,1654,462],{"emptyLinePlaceholder":54},[323,1656,1657],{"class":325,"line":411},[323,1658,1659],{"class":467},"\u002F\u002F Retrieve config values\n",[323,1661,1662,1664,1667,1669,1671,1673,1675,1677,1679,1682,1684,1686,1689],{"class":325,"line":471},[323,1663,666],{"class":488},[323,1665,1666],{"class":329}," retries",[323,1668,495],{"class":480},[323,1670,492],{"class":545},[323,1672,548],{"class":360},[323,1674,1621],{"class":551},[323,1676,504],{"class":360},[323,1678,388],{"class":387},[323,1680,1681],{"class":332},"max-retries",[323,1683,388],{"class":387},[323,1685,685],{"class":360},[323,1687,1688],{"class":346}," 3",[323,1690,514],{"class":360},[323,1692,1693,1695,1698,1700,1702,1704,1706,1708,1710,1713,1715,1717,1719,1722,1724],{"class":325,"line":477},[323,1694,666],{"class":488},[323,1696,1697],{"class":329}," theme",[323,1699,495],{"class":480},[323,1701,492],{"class":545},[323,1703,548],{"class":360},[323,1705,1621],{"class":551},[323,1707,504],{"class":360},[323,1709,388],{"class":387},[323,1711,1712],{"class":332},"theme",[323,1714,388],{"class":387},[323,1716,685],{"class":360},[323,1718,718],{"class":387},[323,1720,1721],{"class":332},"light",[323,1723,388],{"class":387},[323,1725,514],{"class":360},[323,1727,1728,1730,1733,1735,1737,1739,1741,1743,1745,1748,1750,1752,1756],{"class":325,"line":517},[323,1729,666],{"class":488},[323,1731,1732],{"class":329}," newCheckout",[323,1734,495],{"class":480},[323,1736,492],{"class":545},[323,1738,548],{"class":360},[323,1740,1621],{"class":551},[323,1742,504],{"class":360},[323,1744,388],{"class":387},[323,1746,1747],{"class":332},"new-checkout",[323,1749,388],{"class":387},[323,1751,685],{"class":360},[323,1753,1755],{"class":1754},"syTEX"," false",[323,1757,514],{"class":360},[323,1759,1760,1762,1765,1767,1769,1771,1773,1775,1777,1780,1782,1784,1787,1789,1792,1795],{"class":325,"line":522},[323,1761,666],{"class":488},[323,1763,1764],{"class":329}," limits",[323,1766,495],{"class":480},[323,1768,492],{"class":545},[323,1770,548],{"class":360},[323,1772,1621],{"class":551},[323,1774,504],{"class":360},[323,1776,388],{"class":387},[323,1778,1779],{"class":332},"rate-limits",[323,1781,388],{"class":387},[323,1783,685],{"class":360},[323,1785,1786],{"class":480}," default",[323,1788,504],{"class":360},[323,1790,1791],{"class":329},"JsonElement",[323,1793,1794],{"class":360},"));",[323,1796,1797],{"class":467}," \u002F\u002F JSON config\n",[323,1799,1800],{"class":325,"line":528},[323,1801,462],{"emptyLinePlaceholder":54},[323,1803,1804],{"class":325,"line":534},[323,1805,1806],{"class":467},"\u002F\u002F Watch for config updates\n",[323,1808,1809,1811,1814,1816,1818,1820,1822],{"class":325,"line":540},[323,1810,666],{"class":488},[323,1812,1813],{"class":329}," subscription",[323,1815,495],{"class":480},[323,1817,492],{"class":545},[323,1819,548],{"class":360},[323,1821,1487],{"class":551},[323,1823,1824],{"class":360},"(\n",[323,1826,1827,1829,1831,1833],{"class":325,"line":1156},[323,1828,876],{"class":387},[323,1830,1747],{"class":332},[323,1832,388],{"class":387},[323,1834,830],{"class":360},[323,1836,1838,1841],{"class":325,"line":1837},12,[323,1839,1840],{"class":1754},"    false",[323,1842,830],{"class":360},[323,1844,1846,1849,1852,1855,1857,1859,1861,1864,1867,1870,1873,1876,1878],{"class":325,"line":1845},13,[323,1847,1848],{"class":545},"    value =",[323,1850,1851],{"class":480},">",[323,1853,1854],{"class":545}," Console",[323,1856,548],{"class":360},[323,1858,1354],{"class":551},[323,1860,504],{"class":360},[323,1862,1863],{"class":387},"$\"",[323,1865,1866],{"class":332},"new-checkout is now ",[323,1868,1869],{"class":387},"{",[323,1871,1872],{"class":545},"value",[323,1874,1875],{"class":387},"}",[323,1877,388],{"class":387},[323,1879,1385],{"class":360},[323,1881,1883],{"class":325,"line":1882},14,[323,1884,462],{"emptyLinePlaceholder":54},[323,1886,1888],{"class":325,"line":1887},15,[323,1889,1890],{"class":467},"\u002F\u002F Dispose the subscription when it is no longer needed\n",[323,1892,1894,1897,1899,1902],{"class":325,"line":1893},16,[323,1895,1896],{"class":545},"subscription",[323,1898,548],{"class":360},[323,1900,1901],{"class":551},"Dispose",[323,1903,555],{"class":360},[266,1905,1906],{},"The type a config is read as is decided by the overload you call, not by how the config was declared in the dashboard. There is one overload per type the SDK can read exactly, so a type it cannot fill is a compile error rather than a surprise at runtime. Each one takes the value to return when the config is missing, the service is unreachable, or the value will not read as the requested type — so the default should always be the safe choice:",[930,1908,1909,1914,1919,1924,1929,1934,1939,1944],{},[427,1910,1911],{},[273,1912,1913],{},"GetValue(string configKey, bool defaultValue, Context? context = null)",[427,1915,1916],{},[273,1917,1918],{},"GetValue(string configKey, string defaultValue, Context? context = null)",[427,1920,1921],{},[273,1922,1923],{},"GetValue(string configKey, int defaultValue, Context? context = null)",[427,1925,1926],{},[273,1927,1928],{},"GetValue(string configKey, long defaultValue, Context? context = null)",[427,1930,1931],{},[273,1932,1933],{},"GetValue(string configKey, double defaultValue, Context? context = null)",[427,1935,1936],{},[273,1937,1938],{},"GetValue(string configKey, float defaultValue, Context? context = null)",[427,1940,1941],{},[273,1942,1943],{},"GetValue(string configKey, decimal defaultValue, Context? context = null)",[427,1945,1946],{},[273,1947,1948],{},"GetValue(string configKey, JsonElement defaultValue, Context? context = null)",[266,1950,1951],{},"A few of those are worth calling out:",[930,1953,1954,1964,1975],{},[427,1955,1956,1957,1959,1960,1963],{},"Reading as ",[273,1958,1359],{}," returns the value as the server spelled it, with no parsing, so any config reads as text: a boolean config gives ",[273,1961,1962],{},"\"true\"",", and a JSON config gives its JSON.",[427,1965,1966,1967,276,1969,1971,1972,1974],{},"Only ",[273,1968,1577],{},[273,1970,1581],{}," read as a boolean, in either casing. A config holding ",[273,1973,978],{}," yields the default.",[427,1976,1977,1978,945,1981,1984,1985,1988,1989,1992,1993,1996],{},"A whole number the server wrote as ",[273,1979,1980],{},"26.0",[273,1982,1983],{},"2.6e1"," still reads as ",[273,1986,1987],{},"26",". A value a ",[273,1990,1991],{},"float"," cannot hold, such as ",[273,1994,1995],{},"1e300",", yields the default rather than an infinity.",[599,1998,2000],{"id":1999},"json-configs","JSON configs",[266,2002,2003,2005,2006,2008,2009,2012],{},[273,2004,1621],{}," with a ",[273,2007,1791],{}," default returns the config's JSON whole, whatever shape it is. ",[273,2010,2011],{},"GetJsonValue\u003CT>"," binds it to a type of your own instead:",[313,2014,2016],{"className":439,"code":2015,"filename":1629,"language":442,"meta":319,"style":319},"using System.Text.Json;\n\n\u002F\u002F The shape lives in the dashboard, so read it as it stands\nvar raw = client.GetValue(\"rate-limits\", default(JsonElement));\n\n\u002F\u002F The shape belongs to this application, so bind it\nvar limits = client.GetJsonValue(\"rate-limits\", new RateLimits());\n\npublic sealed record RateLimits\n{\n    public int PerMinute { get; init; } = 60;\n}\n",[273,2017,2018,2034,2038,2043,2076,2080,2085,2118,2122,2137,2141,2174],{"__ignoreMap":319},[323,2019,2020,2022,2024,2026,2028,2030,2032],{"class":325,"line":326},[323,2021,450],{"class":449},[323,2023,1638],{"class":453},[323,2025,548],{"class":360},[323,2027,1643],{"class":453},[323,2029,548],{"class":360},[323,2031,1648],{"class":453},[323,2033,457],{"class":360},[323,2035,2036],{"class":325,"line":371},[323,2037,462],{"emptyLinePlaceholder":54},[323,2039,2040],{"class":325,"line":411},[323,2041,2042],{"class":467},"\u002F\u002F The shape lives in the dashboard, so read it as it stands\n",[323,2044,2045,2047,2050,2052,2054,2056,2058,2060,2062,2064,2066,2068,2070,2072,2074],{"class":325,"line":471},[323,2046,666],{"class":488},[323,2048,2049],{"class":329}," raw",[323,2051,495],{"class":480},[323,2053,492],{"class":545},[323,2055,548],{"class":360},[323,2057,1621],{"class":551},[323,2059,504],{"class":360},[323,2061,388],{"class":387},[323,2063,1779],{"class":332},[323,2065,388],{"class":387},[323,2067,685],{"class":360},[323,2069,1786],{"class":480},[323,2071,504],{"class":360},[323,2073,1791],{"class":329},[323,2075,1385],{"class":360},[323,2077,2078],{"class":325,"line":477},[323,2079,462],{"emptyLinePlaceholder":54},[323,2081,2082],{"class":325,"line":517},[323,2083,2084],{"class":467},"\u002F\u002F The shape belongs to this application, so bind it\n",[323,2086,2087,2089,2091,2093,2095,2097,2100,2102,2104,2106,2108,2110,2112,2115],{"class":325,"line":522},[323,2088,666],{"class":488},[323,2090,1764],{"class":329},[323,2092,495],{"class":480},[323,2094,492],{"class":545},[323,2096,548],{"class":360},[323,2098,2099],{"class":551},"GetJsonValue",[323,2101,504],{"class":360},[323,2103,388],{"class":387},[323,2105,1779],{"class":332},[323,2107,388],{"class":387},[323,2109,685],{"class":360},[323,2111,498],{"class":480},[323,2113,2114],{"class":329}," RateLimits",[323,2116,2117],{"class":360},"());\n",[323,2119,2120],{"class":325,"line":528},[323,2121,462],{"emptyLinePlaceholder":54},[323,2123,2124,2128,2131,2134],{"class":325,"line":534},[323,2125,2127],{"class":2126},"sbsja","public",[323,2129,2130],{"class":2126}," sealed",[323,2132,2133],{"class":488}," record",[323,2135,2136],{"class":329}," RateLimits\n",[323,2138,2139],{"class":325,"line":540},[323,2140,695],{"class":360},[323,2142,2143,2146,2149,2152,2154,2157,2159,2162,2164,2167,2169,2172],{"class":325,"line":1156},[323,2144,2145],{"class":2126},"    public",[323,2147,2148],{"class":480}," int",[323,2150,2151],{"class":329}," PerMinute",[323,2153,710],{"class":360},[323,2155,2156],{"class":488}," get",[323,2158,1424],{"class":360},[323,2160,2161],{"class":488}," init",[323,2163,1424],{"class":360},[323,2165,2166],{"class":360}," }",[323,2168,495],{"class":480},[323,2170,2171],{"class":346}," 60",[323,2173,457],{"class":360},[323,2175,2176],{"class":325,"line":1837},[323,2177,920],{"class":360},[2179,2180,2181,2183,2184,2187,2188,2190,2191,2193],"note",{},[273,2182,2011],{}," binds by System.Text.Json's rules, so any property ",[273,2185,2186],{},"T"," does not declare is dropped. A config whose shape has moved on binds to ",[273,2189,2186],{},"'s own defaults and cannot be told apart from the default value you passed. Read the config as a ",[273,2192,1791],{}," when that matters.",[2179,2195,2196,2197,548],{},"Getters never throw when a config is missing or a value will not read as the requested type — they return your default instead. Which of those happened is reported through ",[273,2198,2199],{},"ConfigEvaluated",[599,2201,2203],{"id":2202},"evaluate-config-values-with-a-user-context","Evaluate config values with a user context",[2179,2205,2206],{},"Unlike client SDKs, the server SDKs are able to evaluate targeting rules for the given user context locally without additional network calls.",[266,2208,2209,2210,2213],{},"Every getter takes an optional ",[273,2211,2212],{},"Context"," as its last argument, which is what targeting rules are evaluated against. The same key can therefore resolve differently per user:",[266,2215,2216],{},"The user context can be provided as the last argument to any of the getters. Unlike client SDKs, the server SDKs are able to evaluate targeting rules for the given user context locally without additional network calls.",[313,2218,2220],{"className":439,"code":2219,"filename":1629,"language":442,"meta":319,"style":319},"using ConfigDirector;\n\nvar context = new Context\n{\n    Id = \"12345\",\n    Name = \"Example User\",\n    Traits =\n    {\n        [\"region\"] = \"North America\", \u002F\u002F Any arbitrary traits which can be referenced in targeting rules\n    },\n};\n\nclient.GetValue(\"my-boolean-config-key\", false, context);\n",[273,2221,2222,2230,2234,2248,2252,2268,2284,2291,2295,2324,2328,2333,2337],{"__ignoreMap":319},[323,2223,2224,2226,2228],{"class":325,"line":326},[323,2225,450],{"class":449},[323,2227,454],{"class":453},[323,2229,457],{"class":360},[323,2231,2232],{"class":325,"line":371},[323,2233,462],{"emptyLinePlaceholder":54},[323,2235,2236,2238,2241,2243,2245],{"class":325,"line":411},[323,2237,666],{"class":488},[323,2239,2240],{"class":329}," context",[323,2242,495],{"class":480},[323,2244,498],{"class":480},[323,2246,2247],{"class":329}," Context\n",[323,2249,2250],{"class":325,"line":471},[323,2251,695],{"class":360},[323,2253,2254,2257,2259,2261,2264,2266],{"class":325,"line":477},[323,2255,2256],{"class":545},"    Id ",[323,2258,384],{"class":480},[323,2260,718],{"class":387},[323,2262,2263],{"class":332},"12345",[323,2265,388],{"class":387},[323,2267,830],{"class":360},[323,2269,2270,2273,2275,2277,2280,2282],{"class":325,"line":517},[323,2271,2272],{"class":545},"    Name ",[323,2274,384],{"class":480},[323,2276,718],{"class":387},[323,2278,2279],{"class":332},"Example User",[323,2281,388],{"class":387},[323,2283,830],{"class":360},[323,2285,2286,2289],{"class":325,"line":522},[323,2287,2288],{"class":545},"    Traits ",[323,2290,1084],{"class":480},[323,2292,2293],{"class":325,"line":528},[323,2294,1089],{"class":360},[323,2296,2297,2300,2302,2305,2307,2310,2312,2314,2317,2319,2321],{"class":325,"line":534},[323,2298,2299],{"class":360},"        [",[323,2301,388],{"class":387},[323,2303,2304],{"class":332},"region",[323,2306,388],{"class":387},[323,2308,2309],{"class":360},"]",[323,2311,495],{"class":480},[323,2313,718],{"class":387},[323,2315,2316],{"class":332},"North America",[323,2318,388],{"class":387},[323,2320,685],{"class":360},[323,2322,2323],{"class":467}," \u002F\u002F Any arbitrary traits which can be referenced in targeting rules\n",[323,2325,2326],{"class":325,"line":540},[323,2327,1153],{"class":360},[323,2329,2330],{"class":325,"line":1156},[323,2331,2332],{"class":360},"};\n",[323,2334,2335],{"class":325,"line":1837},[323,2336,462],{"emptyLinePlaceholder":54},[323,2338,2339,2341,2343,2345,2347,2349,2352,2354,2356,2358,2360,2362],{"class":325,"line":1845},[323,2340,1394],{"class":545},[323,2342,548],{"class":360},[323,2344,1621],{"class":551},[323,2346,504],{"class":360},[323,2348,388],{"class":387},[323,2350,2351],{"class":332},"my-boolean-config-key",[323,2353,388],{"class":387},[323,2355,685],{"class":360},[323,2357,1755],{"class":1754},[323,2359,685],{"class":360},[323,2361,2240],{"class":545},[323,2363,514],{"class":360},[266,2365,2366,2367,868],{},"It can also be provided as the fourth argument to ",[273,2368,1487],{},[313,2370,2372],{"className":439,"code":2371,"filename":1629,"language":442,"meta":319,"style":319},"using ConfigDirector;\n\nvar subscription = client.Watch(\n    \"new-checkout\",\n    false,\n    value => Console.WriteLine($\"new-checkout is now {value}\"),\n    new Context\n    {\n        Id = \"12345\",\n        Name = \"Example User\",\n        Traits = { [\"region\"] = \"North America\" },\n    });\n",[273,2373,2374,2382,2386,2402,2412,2418,2446,2453,2457,2472,2487,2517],{"__ignoreMap":319},[323,2375,2376,2378,2380],{"class":325,"line":326},[323,2377,450],{"class":449},[323,2379,454],{"class":453},[323,2381,457],{"class":360},[323,2383,2384],{"class":325,"line":371},[323,2385,462],{"emptyLinePlaceholder":54},[323,2387,2388,2390,2392,2394,2396,2398,2400],{"class":325,"line":411},[323,2389,666],{"class":488},[323,2391,1813],{"class":329},[323,2393,495],{"class":480},[323,2395,492],{"class":545},[323,2397,548],{"class":360},[323,2399,1487],{"class":551},[323,2401,1824],{"class":360},[323,2403,2404,2406,2408,2410],{"class":325,"line":471},[323,2405,876],{"class":387},[323,2407,1747],{"class":332},[323,2409,388],{"class":387},[323,2411,830],{"class":360},[323,2413,2414,2416],{"class":325,"line":477},[323,2415,1840],{"class":1754},[323,2417,830],{"class":360},[323,2419,2420,2422,2424,2426,2428,2430,2432,2434,2436,2438,2440,2442,2444],{"class":325,"line":517},[323,2421,1848],{"class":545},[323,2423,1851],{"class":480},[323,2425,1854],{"class":545},[323,2427,548],{"class":360},[323,2429,1354],{"class":551},[323,2431,504],{"class":360},[323,2433,1863],{"class":387},[323,2435,1866],{"class":332},[323,2437,1869],{"class":387},[323,2439,1872],{"class":545},[323,2441,1875],{"class":387},[323,2443,388],{"class":387},[323,2445,1128],{"class":360},[323,2447,2448,2451],{"class":325,"line":522},[323,2449,2450],{"class":480},"    new",[323,2452,2247],{"class":329},[323,2454,2455],{"class":325,"line":528},[323,2456,1089],{"class":360},[323,2458,2459,2462,2464,2466,2468,2470],{"class":325,"line":534},[323,2460,2461],{"class":545},"        Id ",[323,2463,384],{"class":480},[323,2465,718],{"class":387},[323,2467,2263],{"class":332},[323,2469,388],{"class":387},[323,2471,830],{"class":360},[323,2473,2474,2477,2479,2481,2483,2485],{"class":325,"line":540},[323,2475,2476],{"class":545},"        Name ",[323,2478,384],{"class":480},[323,2480,718],{"class":387},[323,2482,2279],{"class":332},[323,2484,388],{"class":387},[323,2486,830],{"class":360},[323,2488,2489,2492,2494,2496,2499,2501,2503,2505,2507,2509,2511,2513,2515],{"class":325,"line":1156},[323,2490,2491],{"class":545},"        Traits ",[323,2493,384],{"class":480},[323,2495,710],{"class":360},[323,2497,2498],{"class":360}," [",[323,2500,388],{"class":387},[323,2502,2304],{"class":332},[323,2504,388],{"class":387},[323,2506,2309],{"class":360},[323,2508,495],{"class":480},[323,2510,718],{"class":387},[323,2512,2316],{"class":332},[323,2514,388],{"class":387},[323,2516,740],{"class":360},[323,2518,2519],{"class":325,"line":1837},[323,2520,2521],{"class":360},"    });\n",[266,2523,2524,2526],{},[273,2525,2212],{}," is a record and accepts the following:",[930,2528,2529,2539,2549,2569],{},[427,2530,2531,2534],{},[273,2532,2533],{},"Id",[930,2535,2536],{},[427,2537,2538],{},"The user's identifier. It decides their bucket in a percentage rollout, so changing it can move a user into a different percentile. If it is not provided, a percentage rollout assigns an unstable bucket.",[427,2540,2541,2544],{},[273,2542,2543],{},"Name",[930,2545,2546],{},[427,2547,2548],{},"The user's display name.",[427,2550,2551,2554],{},[273,2552,2553],{},"Traits",[930,2555,2556,2566],{},[427,2557,2558,2559,276,2562,2565],{},"Arbitrary traits which can be referenced in targeting rules, keyed by the name the rule references. Names are matched exactly, as JSON member names are. Values are JSON-shaped: strings, numbers, and booleans convert implicitly, and arrays of those convert too. Nested shapes are built with ",[273,2560,2561],{},"TraitValue.FromArray",[273,2563,2564],{},"TraitValue.FromObject",". A value with no text form — null, a list, a nested object — will not match a targeting rule that compares text.",[427,2567,2568],{},"It is never null: a context with no traits carries an empty collection, and assigning a collection copies it.",[427,2570,2571,2574],{},[273,2572,2573],{},"Anonymous",[930,2575,2576],{},[427,2577,2578],{},"Keeps the context out of the dashboard: it is evaluated but never persisted, and telemetry reports neither the context nor its id.",[313,2580,2582],{"className":439,"code":2581,"filename":1629,"language":442,"meta":319,"style":319},"using ConfigDirector;\n\nvar context = new Context\n{\n    Id = \"user-id\",\n    Name = \"Example User\",\n    Traits =\n    {\n        [\"region\"] = \"North America\",\n        [\"age\"] = 26,\n        [\"tags\"] = new[] { \"beta\", \"internal\" },\n    },\n};\n",[273,2583,2584,2592,2596,2608,2612,2627,2641,2647,2651,2673,2693,2733,2737],{"__ignoreMap":319},[323,2585,2586,2588,2590],{"class":325,"line":326},[323,2587,450],{"class":449},[323,2589,454],{"class":453},[323,2591,457],{"class":360},[323,2593,2594],{"class":325,"line":371},[323,2595,462],{"emptyLinePlaceholder":54},[323,2597,2598,2600,2602,2604,2606],{"class":325,"line":411},[323,2599,666],{"class":488},[323,2601,2240],{"class":329},[323,2603,495],{"class":480},[323,2605,498],{"class":480},[323,2607,2247],{"class":329},[323,2609,2610],{"class":325,"line":471},[323,2611,695],{"class":360},[323,2613,2614,2616,2618,2620,2623,2625],{"class":325,"line":477},[323,2615,2256],{"class":545},[323,2617,384],{"class":480},[323,2619,718],{"class":387},[323,2621,2622],{"class":332},"user-id",[323,2624,388],{"class":387},[323,2626,830],{"class":360},[323,2628,2629,2631,2633,2635,2637,2639],{"class":325,"line":517},[323,2630,2272],{"class":545},[323,2632,384],{"class":480},[323,2634,718],{"class":387},[323,2636,2279],{"class":332},[323,2638,388],{"class":387},[323,2640,830],{"class":360},[323,2642,2643,2645],{"class":325,"line":522},[323,2644,2288],{"class":545},[323,2646,1084],{"class":480},[323,2648,2649],{"class":325,"line":528},[323,2650,1089],{"class":360},[323,2652,2653,2655,2657,2659,2661,2663,2665,2667,2669,2671],{"class":325,"line":534},[323,2654,2299],{"class":360},[323,2656,388],{"class":387},[323,2658,2304],{"class":332},[323,2660,388],{"class":387},[323,2662,2309],{"class":360},[323,2664,495],{"class":480},[323,2666,718],{"class":387},[323,2668,2316],{"class":332},[323,2670,388],{"class":387},[323,2672,830],{"class":360},[323,2674,2675,2677,2679,2682,2684,2686,2688,2691],{"class":325,"line":540},[323,2676,2299],{"class":360},[323,2678,388],{"class":387},[323,2680,2681],{"class":332},"age",[323,2683,388],{"class":387},[323,2685,2309],{"class":360},[323,2687,495],{"class":480},[323,2689,2690],{"class":346}," 26",[323,2692,830],{"class":360},[323,2694,2695,2697,2699,2702,2704,2706,2708,2710,2713,2715,2717,2720,2722,2724,2726,2729,2731],{"class":325,"line":1156},[323,2696,2299],{"class":360},[323,2698,388],{"class":387},[323,2700,2701],{"class":332},"tags",[323,2703,388],{"class":387},[323,2705,2309],{"class":360},[323,2707,495],{"class":480},[323,2709,498],{"class":480},[323,2711,2712],{"class":360},"[]",[323,2714,710],{"class":360},[323,2716,718],{"class":387},[323,2718,2719],{"class":332},"beta",[323,2721,388],{"class":387},[323,2723,685],{"class":360},[323,2725,718],{"class":387},[323,2727,2728],{"class":332},"internal",[323,2730,388],{"class":387},[323,2732,740],{"class":360},[323,2734,2735],{"class":325,"line":1837},[323,2736,1153],{"class":360},[323,2738,2739],{"class":325,"line":1845},[323,2740,2332],{"class":360},[599,2742,2744],{"id":2743},"watch-for-updates","Watch for updates",[266,2746,2747,2749,2750,2752,2753,2756,2757,548],{},[273,2748,1487],{}," accepts four arguments, the first is the config key, the second argument is the default value, the third argument is a handler that will be executed when the config value is updated, and the fourth and optional argument is a user context. It has the same set of typed overloads as ",[273,2751,1621],{},", plus ",[273,2754,2755],{},"WatchJson\u003CT>"," as the counterpart to ",[273,2758,2011],{},[266,2760,2761,2762,2764],{},"Registering a watch before ",[273,2763,552],{}," means it is called for the first config state as well; one registered afterwards only sees later updates. When a full payload no longer includes the watched config, the handler is called with the default value, so it always agrees with what the getter would return. Handlers run on the thread the update arrived on, so one that blocks delays later updates.",[313,2766,2768],{"className":439,"code":2767,"filename":1629,"language":442,"meta":319,"style":319},"using ConfigDirector;\n\nvar subscription = client.Watch(\n    \"new-checkout\",\n    false,\n    value => Console.WriteLine($\"new-checkout is now {value}\"),\n    new Context\n    {\n        Id = \"user-id\",\n        Name = \"Example User\",\n        Traits = { [\"region\"] = \"North America\" },\n    });\n",[273,2769,2770,2778,2782,2798,2808,2814,2842,2848,2852,2866,2880,2908],{"__ignoreMap":319},[323,2771,2772,2774,2776],{"class":325,"line":326},[323,2773,450],{"class":449},[323,2775,454],{"class":453},[323,2777,457],{"class":360},[323,2779,2780],{"class":325,"line":371},[323,2781,462],{"emptyLinePlaceholder":54},[323,2783,2784,2786,2788,2790,2792,2794,2796],{"class":325,"line":411},[323,2785,666],{"class":488},[323,2787,1813],{"class":329},[323,2789,495],{"class":480},[323,2791,492],{"class":545},[323,2793,548],{"class":360},[323,2795,1487],{"class":551},[323,2797,1824],{"class":360},[323,2799,2800,2802,2804,2806],{"class":325,"line":471},[323,2801,876],{"class":387},[323,2803,1747],{"class":332},[323,2805,388],{"class":387},[323,2807,830],{"class":360},[323,2809,2810,2812],{"class":325,"line":477},[323,2811,1840],{"class":1754},[323,2813,830],{"class":360},[323,2815,2816,2818,2820,2822,2824,2826,2828,2830,2832,2834,2836,2838,2840],{"class":325,"line":517},[323,2817,1848],{"class":545},[323,2819,1851],{"class":480},[323,2821,1854],{"class":545},[323,2823,548],{"class":360},[323,2825,1354],{"class":551},[323,2827,504],{"class":360},[323,2829,1863],{"class":387},[323,2831,1866],{"class":332},[323,2833,1869],{"class":387},[323,2835,1872],{"class":545},[323,2837,1875],{"class":387},[323,2839,388],{"class":387},[323,2841,1128],{"class":360},[323,2843,2844,2846],{"class":325,"line":522},[323,2845,2450],{"class":480},[323,2847,2247],{"class":329},[323,2849,2850],{"class":325,"line":528},[323,2851,1089],{"class":360},[323,2853,2854,2856,2858,2860,2862,2864],{"class":325,"line":534},[323,2855,2461],{"class":545},[323,2857,384],{"class":480},[323,2859,718],{"class":387},[323,2861,2622],{"class":332},[323,2863,388],{"class":387},[323,2865,830],{"class":360},[323,2867,2868,2870,2872,2874,2876,2878],{"class":325,"line":540},[323,2869,2476],{"class":545},[323,2871,384],{"class":480},[323,2873,718],{"class":387},[323,2875,2279],{"class":332},[323,2877,388],{"class":387},[323,2879,830],{"class":360},[323,2881,2882,2884,2886,2888,2890,2892,2894,2896,2898,2900,2902,2904,2906],{"class":325,"line":1156},[323,2883,2491],{"class":545},[323,2885,384],{"class":480},[323,2887,710],{"class":360},[323,2889,2498],{"class":360},[323,2891,388],{"class":387},[323,2893,2304],{"class":332},[323,2895,388],{"class":387},[323,2897,2309],{"class":360},[323,2899,495],{"class":480},[323,2901,718],{"class":387},[323,2903,2316],{"class":332},[323,2905,388],{"class":387},[323,2907,740],{"class":360},[323,2909,2910],{"class":325,"line":1837},[323,2911,2521],{"class":360},[266,2913,2914,2916,2917,2920],{},[273,2915,1487],{}," returns an ",[273,2918,2919],{},"IDisposable"," that cancels the watch when disposed. Disposing it twice is harmless.",[261,2922,2924],{"id":2923},"other-useful-client-features","Other useful client features",[266,2926,2927],{},"The client provides additional members.",[599,2929,2931],{"id":2930},"isready",[273,2932,570],{},[266,2934,2935,2936,2938,2939,2941],{},"Returns a boolean indicating if the client has received config state and is ready to evaluate configs. It is initially ",[273,2937,1581],{}," and becomes ",[273,2940,1577],{}," once the first config state arrives. Until it does, every getter returns its default.",[599,2943,2945],{"id":2944},"isclosed",[273,2946,2947],{},"IsClosed",[266,2949,2950],{},"Returns a boolean indicating if the client has been disposed. A disposed client cannot be reopened.",[599,2952,2954],{"id":2953},"getallconfigs",[273,2955,2956],{},"GetAllConfigs",[266,2958,2959,2960,2963,2964,2966],{},"Returns every config the client currently holds as an ",[273,2961,2962],{},"IReadOnlyDictionary\u003Cstring, ConfigState>",", evaluated but before type parsing. It optionally accepts a ",[273,2965,2212],{}," and a collection of config keys to restrict the result to.",[266,2968,2969],{},"This is intended for handing state to a client SDK to hydrate with. It records no telemetry, since the SDK that receives the state reports its own evaluations.",[599,2971,2973],{"id":2972},"unwatch",[273,2974,2975],{},"Unwatch",[266,2977,2978],{},"Cancels every watch on one config key.",[599,2980,2982],{"id":2981},"unwatchall",[273,2983,2984],{},"UnwatchAll",[266,2986,2987],{},"Cancels every watch on every config key.",[599,2989,2991],{"id":2990},"disposing-the-client","Disposing the client",[266,2993,2994],{},"Disposing closes all connections to ConfigDirector services, reports whatever telemetry is pending, and cancels every watch and event handler. Disposing twice is harmless.",[266,2996,2997,2998,3001,3002,276,3004,3007],{},"Only dispose when your application shuts down and it will no longer make use of the client instance. ",[273,2999,3000],{},"ConfigDirectorClient"," implements both ",[273,3003,2919],{},[273,3005,3006],{},"IAsyncDisposable","; prefer the asynchronous one, which lets the final telemetry flush complete without blocking a thread.",[266,3009,3010],{},"In an ASP.NET Core application, register the client as a singleton and let the host own the lifecycle — it disposes singletons on shutdown:",[313,3012,3014],{"className":439,"code":3013,"filename":1629,"language":442,"meta":319,"style":319},"using ConfigDirector;\n\nbuilder.Services.AddSingleton\u003CIConfigDirectorClient>(services =>\n    new ConfigDirectorClient(\n        builder.Configuration[\"ConfigDirector:ServerSdkKey\"]!,\n        new ConfigDirectorClientOptions\n        {\n            LoggerFactory = services.GetRequiredService\u003CILoggerFactory>(),\n        }));\n\nvar app = builder.Build();\n\n\u002F\u002F Awaited before the server starts listening, so requests are not served config\n\u002F\u002F defaults while the first config state is still in flight.\nawait app.Services.GetRequiredService\u003CIConfigDirectorClient>().InitializeAsync();\n\napp.Run();\n",[273,3015,3016,3024,3028,3056,3064,3091,3098,3103,3125,3130,3134,3153,3157,3162,3167,3192,3196],{"__ignoreMap":319},[323,3017,3018,3020,3022],{"class":325,"line":326},[323,3019,450],{"class":449},[323,3021,454],{"class":453},[323,3023,457],{"class":360},[323,3025,3026],{"class":325,"line":371},[323,3027,462],{"emptyLinePlaceholder":54},[323,3029,3030,3033,3035,3038,3040,3043,3045,3048,3051,3054],{"class":325,"line":411},[323,3031,3032],{"class":545},"builder",[323,3034,548],{"class":360},[323,3036,3037],{"class":545},"Services",[323,3039,548],{"class":360},[323,3041,3042],{"class":551},"AddSingleton",[323,3044,361],{"class":360},[323,3046,3047],{"class":329},"IConfigDirectorClient",[323,3049,3050],{"class":360},">(",[323,3052,3053],{"class":329},"services",[323,3055,1344],{"class":480},[323,3057,3058,3060,3062],{"class":325,"line":471},[323,3059,2450],{"class":480},[323,3061,501],{"class":329},[323,3063,1824],{"class":360},[323,3065,3066,3069,3071,3074,3077,3079,3082,3084,3086,3089],{"class":325,"line":477},[323,3067,3068],{"class":545},"        builder",[323,3070,548],{"class":360},[323,3072,3073],{"class":545},"Configuration",[323,3075,3076],{"class":360},"[",[323,3078,388],{"class":387},[323,3080,3081],{"class":332},"ConfigDirector:ServerSdkKey",[323,3083,388],{"class":387},[323,3085,2309],{"class":360},[323,3087,3088],{"class":480},"!",[323,3090,830],{"class":360},[323,3092,3093,3096],{"class":325,"line":517},[323,3094,3095],{"class":480},"        new",[323,3097,690],{"class":329},[323,3099,3100],{"class":325,"line":522},[323,3101,3102],{"class":360},"        {\n",[323,3104,3105,3108,3110,3113,3115,3118,3120,3122],{"class":325,"line":528},[323,3106,3107],{"class":545},"            LoggerFactory ",[323,3109,384],{"class":480},[323,3111,3112],{"class":545}," services",[323,3114,548],{"class":360},[323,3116,3117],{"class":551},"GetRequiredService",[323,3119,361],{"class":360},[323,3121,781],{"class":329},[323,3123,3124],{"class":360},">(),\n",[323,3126,3127],{"class":325,"line":534},[323,3128,3129],{"class":360},"        }));\n",[323,3131,3132],{"class":325,"line":540},[323,3133,462],{"emptyLinePlaceholder":54},[323,3135,3136,3138,3141,3143,3146,3148,3151],{"class":325,"line":1156},[323,3137,666],{"class":488},[323,3139,3140],{"class":329}," app",[323,3142,495],{"class":480},[323,3144,3145],{"class":545}," builder",[323,3147,548],{"class":360},[323,3149,3150],{"class":551},"Build",[323,3152,555],{"class":360},[323,3154,3155],{"class":325,"line":1837},[323,3156,462],{"emptyLinePlaceholder":54},[323,3158,3159],{"class":325,"line":1845},[323,3160,3161],{"class":467},"\u002F\u002F Awaited before the server starts listening, so requests are not served config\n",[323,3163,3164],{"class":325,"line":1882},[323,3165,3166],{"class":467},"\u002F\u002F defaults while the first config state is still in flight.\n",[323,3168,3169,3171,3173,3175,3177,3179,3181,3183,3185,3188,3190],{"class":325,"line":1887},[323,3170,481],{"class":480},[323,3172,3140],{"class":545},[323,3174,548],{"class":360},[323,3176,3037],{"class":545},[323,3178,548],{"class":360},[323,3180,3117],{"class":551},[323,3182,361],{"class":360},[323,3184,3047],{"class":329},[323,3186,3187],{"class":360},">().",[323,3189,552],{"class":551},[323,3191,555],{"class":360},[323,3193,3194],{"class":325,"line":1893},[323,3195,462],{"emptyLinePlaceholder":54},[323,3197,3199,3202,3204,3207],{"class":325,"line":3198},17,[323,3200,3201],{"class":545},"app",[323,3203,548],{"class":360},[323,3205,3206],{"class":551},"Run",[323,3208,555],{"class":360},[2179,3210,641,3211,3213,3214,3217,3218,3220],{},[273,3212,289],{}," package reduces all of the above to a single ",[273,3215,3216],{},"AddConfigDirector()"," call. See ",[292,3219,295],{"href":294}," below.",[560,3222,3223],{},"Never build a client per request. Each one holds its own connection, initialization does network I\u002FO, and a fresh client serves defaults until its first config state arrives.",[261,3225,295],{"id":3226},"aspnet-core",[266,3228,641,3229,3231],{},[273,3230,289],{}," package replaces the wiring above with one call. It registers the client, binds its settings from configuration, connects before the server starts listening, and lets the host dispose it on shutdown.",[266,3233,3234,3235,3237],{},"It sits on top of this SDK and brings it along, so installing it gives you both. It replaces the wiring only: reading a config is the same ",[273,3236,3047],{}," API either way, and an application that would rather register the client by hand can keep doing so.",[266,3239,3240,3241,3243,3244,3246],{},"The package targets ",[273,3242,275],{}," and requires ",[273,3245,391],{}," 1.7.1 or later.",[599,3248,3250],{"id":3249},"installing-the-aspnet-core-package","Installing the ASP.NET Core package",[266,3252,3253,3254],{},"The package can be installed from NuGet: ",[292,3255,3256],{"href":3256,"rel":3257,"target":308},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FConfigDirector.ServerSdk.AspNetCore",[307],[310,3259,3260,3280],{},[313,3261,3263],{"className":315,"code":3262,"filename":317,"language":318,"meta":319,"style":319},"dotnet add package ConfigDirector.ServerSdk.AspNetCore --version 1.7.1\n",[273,3264,3265],{"__ignoreMap":319},[323,3266,3267,3269,3271,3273,3276,3278],{"class":325,"line":326},[323,3268,253],{"class":329},[323,3270,333],{"class":332},[323,3272,336],{"class":332},[323,3274,3275],{"class":332}," ConfigDirector.ServerSdk.AspNetCore",[323,3277,343],{"class":342},[323,3279,347],{"class":346},[313,3281,3283],{"className":350,"code":3282,"filename":352,"language":353,"meta":319,"style":319},"\u003CItemGroup>\n  \u003CPackageReference Include=\"ConfigDirector.ServerSdk.AspNetCore\" Version=\"1.7.1\" \u002F>\n\u003C\u002FItemGroup>\n",[273,3284,3285,3293,3321],{"__ignoreMap":319},[323,3286,3287,3289,3291],{"class":325,"line":326},[323,3288,361],{"class":360},[323,3290,365],{"class":364},[323,3292,368],{"class":360},[323,3294,3295,3297,3299,3301,3303,3305,3307,3309,3311,3313,3315,3317,3319],{"class":325,"line":371},[323,3296,374],{"class":360},[323,3298,377],{"class":364},[323,3300,381],{"class":380},[323,3302,384],{"class":360},[323,3304,388],{"class":387},[323,3306,289],{"class":332},[323,3308,388],{"class":387},[323,3310,396],{"class":380},[323,3312,384],{"class":360},[323,3314,388],{"class":387},[323,3316,403],{"class":332},[323,3318,388],{"class":387},[323,3320,408],{"class":360},[323,3322,3323,3325,3327],{"class":325,"line":411},[323,3324,414],{"class":360},[323,3326,365],{"class":364},[323,3328,368],{"class":360},[266,3330,3331,3332,3334],{},"There is no need to reference ",[273,3333,391],{}," as well. It arrives as a dependency, which is how a consuming application gets both.",[599,3336,3338],{"id":3337},"register-the-client","Register the client",[313,3340,3342],{"className":439,"code":3341,"filename":1629,"language":442,"meta":319,"style":319},"var builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddConfigDirector();\n\nvar app = builder.Build();\n\napp.Run();\n",[273,3343,3344,3367,3371,3386,3390,3406,3410],{"__ignoreMap":319},[323,3345,3346,3348,3350,3352,3355,3357,3360,3362,3365],{"class":325,"line":326},[323,3347,666],{"class":488},[323,3349,3145],{"class":329},[323,3351,495],{"class":480},[323,3353,3354],{"class":545}," WebApplication",[323,3356,548],{"class":360},[323,3358,3359],{"class":551},"CreateBuilder",[323,3361,504],{"class":360},[323,3363,3364],{"class":545},"args",[323,3366,514],{"class":360},[323,3368,3369],{"class":325,"line":371},[323,3370,462],{"emptyLinePlaceholder":54},[323,3372,3373,3375,3377,3379,3381,3384],{"class":325,"line":411},[323,3374,3032],{"class":545},[323,3376,548],{"class":360},[323,3378,3037],{"class":545},[323,3380,548],{"class":360},[323,3382,3383],{"class":551},"AddConfigDirector",[323,3385,555],{"class":360},[323,3387,3388],{"class":325,"line":471},[323,3389,462],{"emptyLinePlaceholder":54},[323,3391,3392,3394,3396,3398,3400,3402,3404],{"class":325,"line":477},[323,3393,666],{"class":488},[323,3395,3140],{"class":329},[323,3397,495],{"class":480},[323,3399,3145],{"class":545},[323,3401,548],{"class":360},[323,3403,3150],{"class":551},[323,3405,555],{"class":360},[323,3407,3408],{"class":325,"line":517},[323,3409,462],{"emptyLinePlaceholder":54},[323,3411,3412,3414,3416,3418],{"class":325,"line":522},[323,3413,3201],{"class":545},[323,3415,548],{"class":360},[323,3417,3206],{"class":551},[323,3419,555],{"class":360},[266,3421,3422],{},"with the section it binds:",[313,3424,3426],{"className":844,"code":3425,"filename":846,"language":847,"meta":319,"style":319},"{\n  \"ConfigDirector\": {\n    \"Connection\": {\n      \"Mode\": \"Streaming\",\n      \"Timeout\": \"00:00:03\"\n    }\n  }\n}\n",[273,3427,3428,3432,3444,3456,3474,3491,3495,3499],{"__ignoreMap":319},[323,3429,3430],{"class":325,"line":326},[323,3431,695],{"class":360},[323,3433,3434,3436,3438,3440,3442],{"class":325,"line":371},[323,3435,859],{"class":858},[323,3437,840],{"class":862},[323,3439,388],{"class":858},[323,3441,868],{"class":360},[323,3443,871],{"class":360},[323,3445,3446,3448,3450,3452,3454],{"class":325,"line":411},[323,3447,876],{"class":858},[323,3449,612],{"class":879},[323,3451,388],{"class":858},[323,3453,868],{"class":360},[323,3455,871],{"class":360},[323,3457,3458,3460,3462,3464,3466,3468,3470,3472],{"class":325,"line":471},[323,3459,891],{"class":858},[323,3461,936],{"class":346},[323,3463,388],{"class":858},[323,3465,868],{"class":360},[323,3467,718],{"class":387},[323,3469,952],{"class":332},[323,3471,388],{"class":387},[323,3473,830],{"class":360},[323,3475,3476,3478,3480,3482,3484,3486,3489],{"class":325,"line":477},[323,3477,891],{"class":858},[323,3479,997],{"class":346},[323,3481,388],{"class":858},[323,3483,868],{"class":360},[323,3485,718],{"class":387},[323,3487,3488],{"class":332},"00:00:03",[323,3490,905],{"class":387},[323,3492,3493],{"class":325,"line":517},[323,3494,910],{"class":360},[323,3496,3497],{"class":325,"line":522},[323,3498,915],{"class":360},[323,3500,3501],{"class":325,"line":528},[323,3502,920],{"class":360},[266,3504,3505],{},"That one call does everything the manual registration above does:",[930,3507,3508,3514,3524,3533],{},[427,3509,3510,3511,3513],{},"Registers a single ",[273,3512,3047],{}," for the whole application, which the container disposes on shutdown.",[427,3515,3516,3517,3520,3521,3523],{},"Binds ",[273,3518,3519],{},"ConfigDirectorOptions"," from the ",[273,3522,840],{}," configuration section.",[427,3525,3526,3527,3529,3530,3532],{},"Routes the SDK's logging through the host's ",[273,3528,781],{},", so the ",[273,3531,863],{}," configuration already shown controls it.",[427,3534,3535,3536,3538],{},"Awaits ",[273,3537,552],{}," during startup, before the server accepts its first request.",[2179,3540,3541,3543,3544,3547,3548,3550,3551,3553,3554,3556,3557,548],{},[273,3542,3383],{}," lives in the ",[273,3545,3546],{},"Microsoft.Extensions.DependencyInjection"," namespace, so ",[273,3549,1629],{}," needs no ",[273,3552,450],{}," directive for it. Injecting ",[273,3555,3047],{}," into a controller or an endpoint does need ",[273,3558,3559],{},"using ConfigDirector;",[266,3561,3562,3563,3566],{},"The server SDK key is required, and it is validated when the host starts. A missing key therefore fails at startup with an ",[273,3564,3565],{},"OptionsValidationException"," naming the setting, rather than as a client that quietly evaluates every config to its default.",[560,3568,3569,3570,3572],{},"Server SDK keys are secret values. Do not commit them to ",[273,3571,846],{},". Provide them at runtime via environment variables, user secrets, or from a secret store in code.",[266,3574,3575,3576,3578],{},"A key held in a secret store is the usual reason to adjust the bound settings in code. A delegate passed to ",[273,3577,3383],{}," runs after binding, so it wins over configuration:",[313,3580,3582],{"className":439,"code":3581,"filename":1629,"language":442,"meta":319,"style":319},"builder.Services.AddConfigDirector(options => options.ServerSdkKey = secrets.ConfigDirectorKey);\n",[273,3583,3584],{"__ignoreMap":319},[323,3585,3586,3588,3590,3592,3594,3596,3598,3601,3604,3607,3609,3612,3614,3617,3619,3622],{"class":325,"line":326},[323,3587,3032],{"class":545},[323,3589,548],{"class":360},[323,3591,3037],{"class":545},[323,3593,548],{"class":360},[323,3595,3383],{"class":551},[323,3597,504],{"class":360},[323,3599,3600],{"class":329},"options",[323,3602,3603],{"class":480}," =>",[323,3605,3606],{"class":545}," options",[323,3608,548],{"class":360},[323,3610,3611],{"class":545},"ServerSdkKey ",[323,3613,384],{"class":480},[323,3615,3616],{"class":545}," secrets",[323,3618,548],{"class":360},[323,3620,3621],{"class":545},"ConfigDirectorKey",[323,3623,514],{"class":360},[266,3625,3626,3627,3629],{},"To bind somewhere other than the ",[273,3628,840],{}," section, pass the section itself:",[313,3631,3633],{"className":439,"code":3632,"filename":1629,"language":442,"meta":319,"style":319},"builder.Services.AddConfigDirector(builder.Configuration.GetSection(\"Features:ConfigDirector\"));\n",[273,3634,3635],{"__ignoreMap":319},[323,3636,3637,3639,3641,3643,3645,3647,3649,3651,3653,3655,3657,3660,3662,3664,3667,3669],{"class":325,"line":326},[323,3638,3032],{"class":545},[323,3640,548],{"class":360},[323,3642,3037],{"class":545},[323,3644,548],{"class":360},[323,3646,3383],{"class":551},[323,3648,504],{"class":360},[323,3650,3032],{"class":545},[323,3652,548],{"class":360},[323,3654,3073],{"class":545},[323,3656,548],{"class":360},[323,3658,3659],{"class":551},"GetSection",[323,3661,504],{"class":360},[323,3663,388],{"class":387},[323,3665,3666],{"class":332},"Features:ConfigDirector",[323,3668,388],{"class":387},[323,3670,1385],{"class":360},[266,3672,3673,3674,3677],{},"Both forms also accept the delegate, so ",[273,3675,3676],{},"AddConfigDirector(section, options => ...)"," binds and then adjusts.",[2179,3679,3680,3681,3684,3685,3687,3688,3691,3692,3220],{},"The client is registered with ",[273,3682,3683],{},"TryAdd",", so an ",[273,3686,3047],{}," already present in the service collection is left alone. To test the application without the real client ever being built, register a test client with ",[273,3689,3690],{},"AddConfigDirectorTestClient","; see ",[292,3693,3695],{"href":3694},"#test-your-code","Test your code",[599,3697,3699],{"id":3698},"aspnet-core-configuration-options","ASP.NET Core configuration options",[266,3701,3702,3703,3705],{},"The bound section maps to ",[273,3704,3519],{},", which has the following values:",[930,3707,3708,3718,3731,3748,3762,3784],{},[427,3709,3710,3713],{},[273,3711,3712],{},"ServerSdkKey",[930,3714,3715],{},[427,3716,3717],{},"Your server SDK key. Required.",[427,3719,3720,3723],{},[273,3721,3722],{},"AppName",[930,3724,3725],{},[427,3726,3727,3728,548],{},"The application name that targeting rules can match on. Defaults to the host's ",[273,3729,3730],{},"IHostEnvironment.ApplicationName",[427,3732,3733,3736],{},[273,3734,3735],{},"AppVersion",[930,3737,3738],{},[427,3739,3740,3741,3744,3745,548],{},"The application version that targeting rules match by semver rules. Defaults to the entry assembly's informational version, with any build metadata suffix removed, so ",[273,3742,3743],{},"1.2.3+9f4c1a"," is reported as ",[273,3746,3747],{},"1.2.3",[427,3749,3750,3753],{},[273,3751,3752],{},"RequireReadyOnStartup",[930,3754,3755,3758],{},[427,3756,3757],{},"Whether a host that has not reached ConfigDirector by the end of startup fails to start.",[427,3759,960,3760,548],{},[273,3761,1581],{},[427,3763,3764,3766],{},[273,3765,612],{},[930,3767,3768],{},[427,3769,3770,3771,3774,3775,1371,3777,1371,3779,3781,3782,548],{},"The same ",[273,3772,3773],{},"ConnectionOptions"," described above: ",[273,3776,936],{},[273,3778,967],{},[273,3780,997],{},", and ",[273,3783,630],{},[427,3785,3786,3788],{},[273,3787,615],{},[930,3789,3790],{},[427,3791,3770,3792,3774,3795,276,3797,548],{},[273,3793,3794],{},"TelemetryOptions",[273,3796,1179],{},[273,3798,1195],{},[266,3800,3801,276,3803,3805],{},[273,3802,612],{},[273,3804,615],{}," are the SDK's own option types rather than copies of them, so everything already described for those applies here unchanged:",[313,3807,3809],{"className":844,"code":3808,"filename":846,"language":847,"meta":319,"style":319},"{\n  \"ConfigDirector\": {\n    \"AppName\": \"checkout\",\n    \"AppVersion\": \"1.0.2\",\n    \"RequireReadyOnStartup\": false,\n    \"Connection\": {\n      \"Mode\": \"Polling\",\n      \"PollingInterval\": \"00:10:00\",\n      \"Timeout\": \"00:00:05\"\n    },\n    \"Telemetry\": {\n      \"EventQueueLimit\": 10000,\n      \"FlushInterval\": \"00:00:15\"\n    }\n  }\n}\n",[273,3810,3811,3815,3827,3846,3864,3878,3890,3908,3927,3944,3948,3960,3975,3992,3996,4000],{"__ignoreMap":319},[323,3812,3813],{"class":325,"line":326},[323,3814,695],{"class":360},[323,3816,3817,3819,3821,3823,3825],{"class":325,"line":371},[323,3818,859],{"class":858},[323,3820,840],{"class":862},[323,3822,388],{"class":858},[323,3824,868],{"class":360},[323,3826,871],{"class":360},[323,3828,3829,3831,3833,3835,3837,3839,3842,3844],{"class":325,"line":411},[323,3830,876],{"class":858},[323,3832,3722],{"class":879},[323,3834,388],{"class":858},[323,3836,868],{"class":360},[323,3838,718],{"class":387},[323,3840,3841],{"class":332},"checkout",[323,3843,388],{"class":387},[323,3845,830],{"class":360},[323,3847,3848,3850,3852,3854,3856,3858,3860,3862],{"class":325,"line":471},[323,3849,876],{"class":858},[323,3851,3735],{"class":879},[323,3853,388],{"class":858},[323,3855,868],{"class":360},[323,3857,718],{"class":387},[323,3859,735],{"class":332},[323,3861,388],{"class":387},[323,3863,830],{"class":360},[323,3865,3866,3868,3870,3872,3874,3876],{"class":325,"line":477},[323,3867,876],{"class":858},[323,3869,3752],{"class":879},[323,3871,388],{"class":858},[323,3873,868],{"class":360},[323,3875,1755],{"class":858},[323,3877,830],{"class":360},[323,3879,3880,3882,3884,3886,3888],{"class":325,"line":517},[323,3881,876],{"class":858},[323,3883,612],{"class":879},[323,3885,388],{"class":858},[323,3887,868],{"class":360},[323,3889,871],{"class":360},[323,3891,3892,3894,3896,3898,3900,3902,3904,3906],{"class":325,"line":522},[323,3893,891],{"class":858},[323,3895,936],{"class":346},[323,3897,388],{"class":858},[323,3899,868],{"class":360},[323,3901,718],{"class":387},[323,3903,956],{"class":332},[323,3905,388],{"class":387},[323,3907,830],{"class":360},[323,3909,3910,3912,3914,3916,3918,3920,3923,3925],{"class":325,"line":528},[323,3911,891],{"class":858},[323,3913,967],{"class":346},[323,3915,388],{"class":858},[323,3917,868],{"class":360},[323,3919,718],{"class":387},[323,3921,3922],{"class":332},"00:10:00",[323,3924,388],{"class":387},[323,3926,830],{"class":360},[323,3928,3929,3931,3933,3935,3937,3939,3942],{"class":325,"line":534},[323,3930,891],{"class":858},[323,3932,997],{"class":346},[323,3934,388],{"class":858},[323,3936,868],{"class":360},[323,3938,718],{"class":387},[323,3940,3941],{"class":332},"00:00:05",[323,3943,905],{"class":387},[323,3945,3946],{"class":325,"line":540},[323,3947,1153],{"class":360},[323,3949,3950,3952,3954,3956,3958],{"class":325,"line":1156},[323,3951,876],{"class":858},[323,3953,615],{"class":879},[323,3955,388],{"class":858},[323,3957,868],{"class":360},[323,3959,871],{"class":360},[323,3961,3962,3964,3966,3968,3970,3973],{"class":325,"line":1837},[323,3963,891],{"class":858},[323,3965,1179],{"class":346},[323,3967,388],{"class":858},[323,3969,868],{"class":360},[323,3971,3972],{"class":346}," 10000",[323,3974,830],{"class":360},[323,3976,3977,3979,3981,3983,3985,3987,3990],{"class":325,"line":1845},[323,3978,891],{"class":858},[323,3980,1195],{"class":346},[323,3982,388],{"class":858},[323,3984,868],{"class":360},[323,3986,718],{"class":387},[323,3988,3989],{"class":332},"00:00:15",[323,3991,905],{"class":387},[323,3993,3994],{"class":325,"line":1882},[323,3995,910],{"class":360},[323,3997,3998],{"class":325,"line":1887},[323,3999,915],{"class":360},[323,4001,4002],{"class":325,"line":1893},[323,4003,920],{"class":360},[266,4005,4006],{},"Nested settings follow the usual environment variable convention, with a double underscore between levels:",[313,4008,4010],{"className":315,"code":4009,"language":318,"meta":319,"style":319},"ConfigDirector__ServerSdkKey=YOUR-SERVER-SDK-KEY\nConfigDirector__Connection__Mode=Polling\n",[273,4011,4012,4022],{"__ignoreMap":319},[323,4013,4014,4017,4019],{"class":325,"line":326},[323,4015,4016],{"class":545},"ConfigDirector__ServerSdkKey",[323,4018,384],{"class":480},[323,4020,4021],{"class":332},"YOUR-SERVER-SDK-KEY\n",[323,4023,4024,4027,4029],{"class":325,"line":371},[323,4025,4026],{"class":545},"ConfigDirector__Connection__Mode",[323,4028,384],{"class":480},[323,4030,4031],{"class":332},"Polling\n",[2179,4033,4034],{},"Settings are read once, when the client is first resolved. Reloading configuration afterwards does not reach a client that has already been built.",[599,4036,4038],{"id":4037},"startup-initialization","Startup initialization",[266,4040,4041],{},"The package connects during startup rather than on the first request, and it does so before the server begins listening, so no request is served config defaults while the first config state is still in flight.",[266,4043,4044,4045,4047,4048,868],{},"By default, a host that cannot reach ConfigDirector still starts. It logs a warning, and every config resolves to the default its caller supplied until config state arrives, which is the SDK's own posture. Set ",[273,4046,3752],{}," to fail startup instead, with a ",[273,4049,4050],{},"ConfigDirectorConnectionException",[313,4052,4054],{"className":844,"code":4053,"filename":846,"language":847,"meta":319,"style":319},"{\n  \"ConfigDirector\": {\n    \"RequireReadyOnStartup\": true\n  }\n}\n",[273,4055,4056,4060,4072,4085,4089],{"__ignoreMap":319},[323,4057,4058],{"class":325,"line":326},[323,4059,695],{"class":360},[323,4061,4062,4064,4066,4068,4070],{"class":325,"line":371},[323,4063,859],{"class":858},[323,4065,840],{"class":862},[323,4067,388],{"class":858},[323,4069,868],{"class":360},[323,4071,871],{"class":360},[323,4073,4074,4076,4078,4080,4082],{"class":325,"line":411},[323,4075,876],{"class":858},[323,4077,3752],{"class":879},[323,4079,388],{"class":858},[323,4081,868],{"class":360},[323,4083,4084],{"class":858}," true\n",[323,4086,4087],{"class":325,"line":471},[323,4088,915],{"class":360},[323,4090,4091],{"class":325,"line":477},[323,4092,920],{"class":360},[266,4094,4095],{},"Registering a watch is the one thing that still happens in code, between building the application and running it. Resolving the client there builds it without making any network calls; the connection is opened later, as the host starts. A watch registered in that gap is called for the first config state as well as for the updates after it:",[313,4097,4099],{"className":439,"code":4098,"filename":1629,"language":442,"meta":319,"style":319},"var app = builder.Build();\n\nvar client = app.Services.GetRequiredService\u003CIConfigDirectorClient>();\n\nclient.Watch(\"new-checkout\", false, enabled =>\n    app.Logger.LogInformation(\"new-checkout is now {Enabled}\", enabled));\n\napp.Run();\n",[273,4100,4101,4117,4121,4146,4150,4177,4207,4211],{"__ignoreMap":319},[323,4102,4103,4105,4107,4109,4111,4113,4115],{"class":325,"line":326},[323,4104,666],{"class":488},[323,4106,3140],{"class":329},[323,4108,495],{"class":480},[323,4110,3145],{"class":545},[323,4112,548],{"class":360},[323,4114,3150],{"class":551},[323,4116,555],{"class":360},[323,4118,4119],{"class":325,"line":371},[323,4120,462],{"emptyLinePlaceholder":54},[323,4122,4123,4125,4127,4129,4131,4133,4135,4137,4139,4141,4143],{"class":325,"line":411},[323,4124,666],{"class":488},[323,4126,492],{"class":329},[323,4128,495],{"class":480},[323,4130,3140],{"class":545},[323,4132,548],{"class":360},[323,4134,3037],{"class":545},[323,4136,548],{"class":360},[323,4138,3117],{"class":551},[323,4140,361],{"class":360},[323,4142,3047],{"class":329},[323,4144,4145],{"class":360},">();\n",[323,4147,4148],{"class":325,"line":471},[323,4149,462],{"emptyLinePlaceholder":54},[323,4151,4152,4154,4156,4158,4160,4162,4164,4166,4168,4170,4172,4175],{"class":325,"line":477},[323,4153,1394],{"class":545},[323,4155,548],{"class":360},[323,4157,1487],{"class":551},[323,4159,504],{"class":360},[323,4161,388],{"class":387},[323,4163,1747],{"class":332},[323,4165,388],{"class":387},[323,4167,685],{"class":360},[323,4169,1755],{"class":1754},[323,4171,685],{"class":360},[323,4173,4174],{"class":329}," enabled",[323,4176,1344],{"class":480},[323,4178,4179,4182,4184,4187,4189,4192,4194,4196,4199,4201,4203,4205],{"class":325,"line":517},[323,4180,4181],{"class":545},"    app",[323,4183,548],{"class":360},[323,4185,4186],{"class":545},"Logger",[323,4188,548],{"class":360},[323,4190,4191],{"class":551},"LogInformation",[323,4193,504],{"class":360},[323,4195,388],{"class":387},[323,4197,4198],{"class":332},"new-checkout is now {Enabled}",[323,4200,388],{"class":387},[323,4202,685],{"class":360},[323,4204,4174],{"class":545},[323,4206,1385],{"class":360},[323,4208,4209],{"class":325,"line":522},[323,4210,462],{"emptyLinePlaceholder":54},[323,4212,4213,4215,4217,4219],{"class":325,"line":528},[323,4214,3201],{"class":545},[323,4216,548],{"class":360},[323,4218,3206],{"class":551},[323,4220,555],{"class":360},[599,4222,4224],{"id":4223},"the-user-context-for-a-request","The user context for a request",[266,4226,4227,4230,4231,4233],{},[273,4228,4229],{},"WithContext"," declares once how a request becomes an evaluation ",[273,4232,2212],{},", rather than repeating it in every action:",[313,4235,4237],{"className":439,"code":4236,"filename":1629,"language":442,"meta":319,"style":319},"using ConfigDirector;\n\nbuilder.Services.AddConfigDirector()\n    .WithContext(http => new Context\n    {\n        Id = http.User.FindFirst(\"sub\")?.Value,\n        Traits =\n        {\n            [\"region\"] = http.Request.Headers[\"X-Region\"].ToString(),\n        },\n    });\n",[273,4238,4239,4247,4251,4266,4284,4288,4326,4332,4336,4381,4386],{"__ignoreMap":319},[323,4240,4241,4243,4245],{"class":325,"line":326},[323,4242,450],{"class":449},[323,4244,454],{"class":453},[323,4246,457],{"class":360},[323,4248,4249],{"class":325,"line":371},[323,4250,462],{"emptyLinePlaceholder":54},[323,4252,4253,4255,4257,4259,4261,4263],{"class":325,"line":411},[323,4254,3032],{"class":545},[323,4256,548],{"class":360},[323,4258,3037],{"class":545},[323,4260,548],{"class":360},[323,4262,3383],{"class":551},[323,4264,4265],{"class":360},"()\n",[323,4267,4268,4271,4273,4275,4278,4280,4282],{"class":325,"line":471},[323,4269,4270],{"class":360},"    .",[323,4272,4229],{"class":551},[323,4274,504],{"class":360},[323,4276,4277],{"class":329},"http",[323,4279,3603],{"class":480},[323,4281,498],{"class":480},[323,4283,2247],{"class":329},[323,4285,4286],{"class":325,"line":477},[323,4287,1089],{"class":360},[323,4289,4290,4292,4294,4297,4299,4302,4304,4307,4309,4311,4314,4316,4318,4320,4322,4324],{"class":325,"line":517},[323,4291,2461],{"class":545},[323,4293,384],{"class":480},[323,4295,4296],{"class":545}," http",[323,4298,548],{"class":360},[323,4300,4301],{"class":545},"User",[323,4303,548],{"class":360},[323,4305,4306],{"class":551},"FindFirst",[323,4308,504],{"class":360},[323,4310,388],{"class":387},[323,4312,4313],{"class":332},"sub",[323,4315,388],{"class":387},[323,4317,1341],{"class":360},[323,4319,1327],{"class":480},[323,4321,548],{"class":360},[323,4323,1523],{"class":545},[323,4325,830],{"class":360},[323,4327,4328,4330],{"class":325,"line":522},[323,4329,2491],{"class":545},[323,4331,1084],{"class":480},[323,4333,4334],{"class":325,"line":528},[323,4335,3102],{"class":360},[323,4337,4338,4341,4343,4345,4347,4349,4351,4353,4355,4358,4360,4363,4365,4367,4370,4372,4375,4378],{"class":325,"line":534},[323,4339,4340],{"class":360},"            [",[323,4342,388],{"class":387},[323,4344,2304],{"class":332},[323,4346,388],{"class":387},[323,4348,2309],{"class":360},[323,4350,495],{"class":480},[323,4352,4296],{"class":545},[323,4354,548],{"class":360},[323,4356,4357],{"class":545},"Request",[323,4359,548],{"class":360},[323,4361,4362],{"class":545},"Headers",[323,4364,3076],{"class":360},[323,4366,388],{"class":387},[323,4368,4369],{"class":332},"X-Region",[323,4371,388],{"class":387},[323,4373,4374],{"class":360},"].",[323,4376,4377],{"class":551},"ToString",[323,4379,4380],{"class":360},"(),\n",[323,4382,4383],{"class":325,"line":540},[323,4384,4385],{"class":360},"        },\n",[323,4387,4388],{"class":325,"line":1156},[323,4389,2521],{"class":360},[266,4391,4392,4393,4396,4397,4399],{},"Actions then take an ",[273,4394,4395],{},"IConfigDirectorContextAccessor"," and read ",[273,4398,2212],{}," from it, instead of each one rebuilding the context itself:",[313,4401,4404],{"className":439,"code":4402,"filename":4403,"language":442,"meta":319,"style":319},"using ConfigDirector;\nusing Microsoft.AspNetCore.Mvc;\n\n[ApiController]\n[Route(\"configs\")]\npublic sealed class ConfigsController : ControllerBase\n{\n    private readonly IConfigDirectorClient _client;\n    private readonly IConfigDirectorContextAccessor _context;\n\n    public ConfigsController(IConfigDirectorClient client, IConfigDirectorContextAccessor context)\n    {\n        _client = client;\n        _context = context;\n    }\n\n    [HttpGet]\n    public bool Get() => _client.GetValue(\"new-checkout\", false, _context.Context);\n}\n","ConfigsController.cs",[273,4405,4406,4414,4433,4437,4447,4466,4484,4488,4504,4518,4522,4543,4547,4558,4569,4573,4577,4587,4631],{"__ignoreMap":319},[323,4407,4408,4410,4412],{"class":325,"line":326},[323,4409,450],{"class":449},[323,4411,454],{"class":453},[323,4413,457],{"class":360},[323,4415,4416,4418,4421,4423,4426,4428,4431],{"class":325,"line":371},[323,4417,450],{"class":449},[323,4419,4420],{"class":453}," Microsoft",[323,4422,548],{"class":360},[323,4424,4425],{"class":453},"AspNetCore",[323,4427,548],{"class":360},[323,4429,4430],{"class":453},"Mvc",[323,4432,457],{"class":360},[323,4434,4435],{"class":325,"line":411},[323,4436,462],{"emptyLinePlaceholder":54},[323,4438,4439,4441,4444],{"class":325,"line":471},[323,4440,3076],{"class":360},[323,4442,4443],{"class":329},"ApiController",[323,4445,4446],{"class":360},"]\n",[323,4448,4449,4451,4454,4456,4458,4461,4463],{"class":325,"line":477},[323,4450,3076],{"class":360},[323,4452,4453],{"class":329},"Route",[323,4455,504],{"class":360},[323,4457,388],{"class":387},[323,4459,4460],{"class":332},"configs",[323,4462,388],{"class":387},[323,4464,4465],{"class":360},")]\n",[323,4467,4468,4470,4472,4475,4478,4481],{"class":325,"line":517},[323,4469,2127],{"class":2126},[323,4471,2130],{"class":2126},[323,4473,4474],{"class":488}," class",[323,4476,4477],{"class":329}," ConfigsController",[323,4479,4480],{"class":360}," :",[323,4482,4483],{"class":329}," ControllerBase\n",[323,4485,4486],{"class":325,"line":522},[323,4487,695],{"class":360},[323,4489,4490,4493,4496,4499,4502],{"class":325,"line":528},[323,4491,4492],{"class":2126},"    private",[323,4494,4495],{"class":2126}," readonly",[323,4497,4498],{"class":329}," IConfigDirectorClient",[323,4500,4501],{"class":329}," _client",[323,4503,457],{"class":360},[323,4505,4506,4508,4510,4513,4516],{"class":325,"line":534},[323,4507,4492],{"class":2126},[323,4509,4495],{"class":2126},[323,4511,4512],{"class":329}," IConfigDirectorContextAccessor",[323,4514,4515],{"class":329}," _context",[323,4517,457],{"class":360},[323,4519,4520],{"class":325,"line":540},[323,4521,462],{"emptyLinePlaceholder":54},[323,4523,4524,4526,4528,4530,4532,4534,4536,4538,4540],{"class":325,"line":1156},[323,4525,2145],{"class":2126},[323,4527,4477],{"class":551},[323,4529,504],{"class":360},[323,4531,3047],{"class":329},[323,4533,492],{"class":329},[323,4535,685],{"class":360},[323,4537,4512],{"class":329},[323,4539,2240],{"class":329},[323,4541,4542],{"class":360},")\n",[323,4544,4545],{"class":325,"line":1837},[323,4546,1089],{"class":360},[323,4548,4549,4552,4554,4556],{"class":325,"line":1845},[323,4550,4551],{"class":545},"        _client ",[323,4553,384],{"class":480},[323,4555,492],{"class":545},[323,4557,457],{"class":360},[323,4559,4560,4563,4565,4567],{"class":325,"line":1882},[323,4561,4562],{"class":545},"        _context ",[323,4564,384],{"class":480},[323,4566,2240],{"class":545},[323,4568,457],{"class":360},[323,4570,4571],{"class":325,"line":1887},[323,4572,910],{"class":360},[323,4574,4575],{"class":325,"line":1893},[323,4576,462],{"emptyLinePlaceholder":54},[323,4578,4579,4582,4585],{"class":325,"line":3198},[323,4580,4581],{"class":360},"    [",[323,4583,4584],{"class":329},"HttpGet",[323,4586,4446],{"class":360},[323,4588,4590,4592,4595,4598,4601,4603,4605,4607,4609,4611,4613,4615,4617,4619,4621,4623,4625,4627,4629],{"class":325,"line":4589},18,[323,4591,2145],{"class":2126},[323,4593,4594],{"class":480}," bool",[323,4596,4597],{"class":551}," Get",[323,4599,4600],{"class":360},"()",[323,4602,3603],{"class":480},[323,4604,4501],{"class":545},[323,4606,548],{"class":360},[323,4608,1621],{"class":551},[323,4610,504],{"class":360},[323,4612,388],{"class":387},[323,4614,1747],{"class":332},[323,4616,388],{"class":387},[323,4618,685],{"class":360},[323,4620,1755],{"class":1754},[323,4622,685],{"class":360},[323,4624,4515],{"class":545},[323,4626,548],{"class":360},[323,4628,2212],{"class":545},[323,4630,514],{"class":360},[323,4632,4634],{"class":325,"line":4633},19,[323,4635,920],{"class":360},[266,4637,4638,4639,4641,4642,4644,4645,4647],{},"The delegate runs at most once per request, the first time the context is asked for, so several evaluations in one action cost one call to it. It may return ",[273,4640,1527],{}," to evaluate without a context. ",[273,4643,2212],{}," is also ",[273,4646,1527],{}," when no request is in flight, which is what a background service reading the accessor sees.",[2179,4649,4650,4652,4653,4655],{},[273,4651,4395],{}," is registered only when ",[273,4654,4229],{}," has been called. Injecting it without that fails at resolution, rather than quietly evaluating every config with no context, which would disable targeting without saying so.",[599,4657,4659],{"id":4658},"health-checks","Health checks",[313,4661,4663],{"className":439,"code":4662,"filename":1629,"language":442,"meta":319,"style":319},"builder.Services.AddHealthChecks().AddConfigDirector();\n\nvar app = builder.Build();\n\napp.MapHealthChecks(\"\u002Fhealth\");\n",[273,4664,4665,4685,4689,4705,4709],{"__ignoreMap":319},[323,4666,4667,4669,4671,4673,4675,4678,4681,4683],{"class":325,"line":326},[323,4668,3032],{"class":545},[323,4670,548],{"class":360},[323,4672,3037],{"class":545},[323,4674,548],{"class":360},[323,4676,4677],{"class":551},"AddHealthChecks",[323,4679,4680],{"class":360},"().",[323,4682,3383],{"class":551},[323,4684,555],{"class":360},[323,4686,4687],{"class":325,"line":371},[323,4688,462],{"emptyLinePlaceholder":54},[323,4690,4691,4693,4695,4697,4699,4701,4703],{"class":325,"line":411},[323,4692,666],{"class":488},[323,4694,3140],{"class":329},[323,4696,495],{"class":480},[323,4698,3145],{"class":545},[323,4700,548],{"class":360},[323,4702,3150],{"class":551},[323,4704,555],{"class":360},[323,4706,4707],{"class":325,"line":471},[323,4708,462],{"emptyLinePlaceholder":54},[323,4710,4711,4713,4715,4718,4720,4722,4725,4727],{"class":325,"line":477},[323,4712,3201],{"class":545},[323,4714,548],{"class":360},[323,4716,4717],{"class":551},"MapHealthChecks",[323,4719,504],{"class":360},[323,4721,388],{"class":387},[323,4723,4724],{"class":332},"\u002Fhealth",[323,4726,388],{"class":387},[323,4728,514],{"class":360},[266,4730,4731,4732,4735,4736,4739,4740,4743],{},"The check reports ",[273,4733,4734],{},"Healthy"," once config state has arrived. Until it does, it reports ",[273,4737,4738],{},"Degraded"," rather than ",[273,4741,4742],{},"Unhealthy",": the application still answers every request, with each config resolving to the default its caller supplied, so taking the instance out of rotation is the wrong response to ConfigDirector being unreachable.",[266,4745,4746],{},"Pass a failure status to say otherwise, along with the name the check is registered under and any tags to filter it by:",[313,4748,4750],{"className":439,"code":4749,"filename":1629,"language":442,"meta":319,"style":319},"using Microsoft.Extensions.Diagnostics.HealthChecks;\n\nbuilder.Services.AddHealthChecks()\n    .AddConfigDirector(\n        name: \"configdirector\",\n        failureStatus: HealthStatus.Unhealthy,\n        tags: [\"ready\"]);\n",[273,4751,4752,4775,4779,4793,4801,4817,4833],{"__ignoreMap":319},[323,4753,4754,4756,4758,4760,4763,4765,4768,4770,4773],{"class":325,"line":326},[323,4755,450],{"class":449},[323,4757,4420],{"class":453},[323,4759,548],{"class":360},[323,4761,4762],{"class":453},"Extensions",[323,4764,548],{"class":360},[323,4766,4767],{"class":453},"Diagnostics",[323,4769,548],{"class":360},[323,4771,4772],{"class":453},"HealthChecks",[323,4774,457],{"class":360},[323,4776,4777],{"class":325,"line":371},[323,4778,462],{"emptyLinePlaceholder":54},[323,4780,4781,4783,4785,4787,4789,4791],{"class":325,"line":411},[323,4782,3032],{"class":545},[323,4784,548],{"class":360},[323,4786,3037],{"class":545},[323,4788,548],{"class":360},[323,4790,4677],{"class":551},[323,4792,4265],{"class":360},[323,4794,4795,4797,4799],{"class":325,"line":471},[323,4796,4270],{"class":360},[323,4798,3383],{"class":551},[323,4800,1824],{"class":360},[323,4802,4803,4806,4808,4810,4813,4815],{"class":325,"line":477},[323,4804,4805],{"class":329},"        name",[323,4807,868],{"class":360},[323,4809,718],{"class":387},[323,4811,4812],{"class":332},"configdirector",[323,4814,388],{"class":387},[323,4816,830],{"class":360},[323,4818,4819,4822,4824,4827,4829,4831],{"class":325,"line":517},[323,4820,4821],{"class":329},"        failureStatus",[323,4823,868],{"class":360},[323,4825,4826],{"class":545}," HealthStatus",[323,4828,548],{"class":360},[323,4830,4742],{"class":545},[323,4832,830],{"class":360},[323,4834,4835,4838,4840,4842,4844,4847,4849],{"class":325,"line":522},[323,4836,4837],{"class":329},"        tags",[323,4839,868],{"class":360},[323,4841,2498],{"class":360},[323,4843,388],{"class":387},[323,4845,4846],{"class":332},"ready",[323,4848,388],{"class":387},[323,4850,4851],{"class":360},"]);\n",[266,4853,4854,4857,4858,276,4860,4863,4864,4867,4868,4870],{},[273,4855,4856],{},"name"," defaults to ",[273,4859,4812],{},[273,4861,4862],{},"failureStatus"," to ",[273,4865,4866],{},"HealthStatus.Degraded",". A client that has been disposed always reports ",[273,4869,4742],{},", whatever failure status is configured, since it cannot be reopened.",[261,4872,3695],{"id":4873},"test-your-code",[266,4875,4876,4877,4880,4881,4885],{},"Use the SDK's testing package, ",[273,4878,4879],{},"ConfigDirector.ServerSdk.Testing",", to test the code that reads your configs and flags. It creates a ",[4882,4883,4884],"strong",{},"test client",": the SDK's real client connected to an in-memory server that your test controls. Only the connection to ConfigDirector is replaced. Everything else is the same code that runs in production, so the code under test behaves exactly as it does against ConfigDirector, and no network connection is opened and no telemetry is sent.",[266,4887,4888,4889,4891],{},"The package is released together with the SDK and must be the same version as the ",[273,4890,391],{}," your test project restores; it declares that exact dependency, and creating a test client checks it again. Add it to your test project only:",[313,4893,4895],{"className":315,"code":4894,"filename":317,"language":318,"meta":319,"style":319},"dotnet add package ConfigDirector.ServerSdk.Testing --version 1.7.1\n",[273,4896,4897],{"__ignoreMap":319},[323,4898,4899,4901,4903,4905,4908,4910],{"class":325,"line":326},[323,4900,253],{"class":329},[323,4902,333],{"class":332},[323,4904,336],{"class":332},[323,4906,4907],{"class":332}," ConfigDirector.ServerSdk.Testing",[323,4909,343],{"class":342},[323,4911,347],{"class":346},[313,4913,4916],{"className":439,"code":4914,"filename":4915,"language":442,"meta":319,"style":319},"using ConfigDirector.Testing;\n\nawait using var testClient = ConfigDirectorTesting.CreateTestClient(\n    new Dictionary\u003Cstring, object> { [\"new-checkout\"] = true, [\"max-items\"] = 20 });\nvar service = new CheckoutService(testClient.Client);\nawait testClient.Client.InitializeAsync();\n\nservice.IsNewCheckoutEnabled(\"user-123\").ShouldBeTrue();\n\ntestClient.SetValue(\"new-checkout\", false);\nservice.IsNewCheckoutEnabled(\"user-123\").ShouldBeFalse();\n","CheckoutServiceTests.cs",[273,4917,4918,4931,4935,4958,5014,5040,5056,5060,5087,5091,5114],{"__ignoreMap":319},[323,4919,4920,4922,4924,4926,4929],{"class":325,"line":326},[323,4921,450],{"class":449},[323,4923,454],{"class":453},[323,4925,548],{"class":360},[323,4927,4928],{"class":453},"Testing",[323,4930,457],{"class":360},[323,4932,4933],{"class":325,"line":371},[323,4934,462],{"emptyLinePlaceholder":54},[323,4936,4937,4939,4941,4943,4946,4948,4951,4953,4956],{"class":325,"line":411},[323,4938,481],{"class":480},[323,4940,485],{"class":484},[323,4942,489],{"class":488},[323,4944,4945],{"class":329}," testClient",[323,4947,495],{"class":480},[323,4949,4950],{"class":545}," ConfigDirectorTesting",[323,4952,548],{"class":360},[323,4954,4955],{"class":551},"CreateTestClient",[323,4957,1824],{"class":360},[323,4959,4960,4962,4965,4967,4969,4971,4974,4976,4978,4980,4982,4984,4986,4988,4990,4993,4995,4997,4999,5002,5004,5006,5008,5011],{"class":325,"line":471},[323,4961,2450],{"class":480},[323,4963,4964],{"class":329}," Dictionary",[323,4966,361],{"class":360},[323,4968,1359],{"class":480},[323,4970,685],{"class":360},[323,4972,4973],{"class":480}," object",[323,4975,1851],{"class":360},[323,4977,710],{"class":360},[323,4979,2498],{"class":360},[323,4981,388],{"class":387},[323,4983,1747],{"class":332},[323,4985,388],{"class":387},[323,4987,2309],{"class":360},[323,4989,495],{"class":480},[323,4991,4992],{"class":1754}," true",[323,4994,685],{"class":360},[323,4996,2498],{"class":360},[323,4998,388],{"class":387},[323,5000,5001],{"class":332},"max-items",[323,5003,388],{"class":387},[323,5005,2309],{"class":360},[323,5007,495],{"class":480},[323,5009,5010],{"class":346}," 20",[323,5012,5013],{"class":360}," });\n",[323,5015,5016,5018,5021,5023,5025,5028,5030,5033,5035,5038],{"class":325,"line":477},[323,5017,666],{"class":488},[323,5019,5020],{"class":329}," service",[323,5022,495],{"class":480},[323,5024,498],{"class":480},[323,5026,5027],{"class":329}," CheckoutService",[323,5029,504],{"class":360},[323,5031,5032],{"class":545},"testClient",[323,5034,548],{"class":360},[323,5036,5037],{"class":545},"Client",[323,5039,514],{"class":360},[323,5041,5042,5044,5046,5048,5050,5052,5054],{"class":325,"line":517},[323,5043,481],{"class":480},[323,5045,4945],{"class":545},[323,5047,548],{"class":360},[323,5049,5037],{"class":545},[323,5051,548],{"class":360},[323,5053,552],{"class":551},[323,5055,555],{"class":360},[323,5057,5058],{"class":325,"line":522},[323,5059,462],{"emptyLinePlaceholder":54},[323,5061,5062,5065,5067,5070,5072,5074,5077,5079,5082,5085],{"class":325,"line":528},[323,5063,5064],{"class":545},"service",[323,5066,548],{"class":360},[323,5068,5069],{"class":551},"IsNewCheckoutEnabled",[323,5071,504],{"class":360},[323,5073,388],{"class":387},[323,5075,5076],{"class":332},"user-123",[323,5078,388],{"class":387},[323,5080,5081],{"class":360},").",[323,5083,5084],{"class":551},"ShouldBeTrue",[323,5086,555],{"class":360},[323,5088,5089],{"class":325,"line":534},[323,5090,462],{"emptyLinePlaceholder":54},[323,5092,5093,5095,5097,5100,5102,5104,5106,5108,5110,5112],{"class":325,"line":540},[323,5094,5032],{"class":545},[323,5096,548],{"class":360},[323,5098,5099],{"class":551},"SetValue",[323,5101,504],{"class":360},[323,5103,388],{"class":387},[323,5105,1747],{"class":332},[323,5107,388],{"class":387},[323,5109,685],{"class":360},[323,5111,1755],{"class":1754},[323,5113,514],{"class":360},[323,5115,5116,5118,5120,5122,5124,5126,5128,5130,5132,5135],{"class":325,"line":1156},[323,5117,5064],{"class":545},[323,5119,548],{"class":360},[323,5121,5069],{"class":551},[323,5123,504],{"class":360},[323,5125,388],{"class":387},[323,5127,5076],{"class":332},[323,5129,388],{"class":387},[323,5131,5081],{"class":360},[323,5133,5134],{"class":551},"ShouldBeFalse",[323,5136,555],{"class":360},[266,5138,5139,5142,5143,5145,5146,5148,5149,5151,5152,5155,5156,5158],{},[273,5140,5141],{},"testClient.Client"," is an ",[273,5144,3047],{},", so it goes anywhere your code accepts one. It starts uninitialized, like a production client, because the code under test usually owns the call to ",[273,5147,552],{},"; with no hold or failure armed, ",[273,5150,552],{}," completes at once with the stored values. ",[273,5153,5154],{},"TestClient"," is ",[273,5157,3006],{}," and disposes its client.",[599,5160,5162],{"id":5161},"in-an-aspnet-core-application","In an ASP.NET Core application",[266,5164,5165,5168,5169,5171],{},[273,5166,5167],{},"ConfigDirector.ServerSdk.AspNetCore.Testing"," registers the test client with an application wired up with ",[273,5170,3383],{},", so the application starts without an SDK key, opens no connection, and reads the values the test seeds:",[313,5173,5175],{"className":315,"code":5174,"filename":317,"language":318,"meta":319,"style":319},"dotnet add package ConfigDirector.ServerSdk.AspNetCore.Testing --version 1.7.1\n",[273,5176,5177],{"__ignoreMap":319},[323,5178,5179,5181,5183,5185,5188,5190],{"class":325,"line":326},[323,5180,253],{"class":329},[323,5182,333],{"class":332},[323,5184,336],{"class":332},[323,5186,5187],{"class":332}," ConfigDirector.ServerSdk.AspNetCore.Testing",[323,5189,343],{"class":342},[323,5191,347],{"class":346},[313,5193,5196],{"className":439,"code":5194,"filename":5195,"language":442,"meta":319,"style":319},"using ConfigDirector.Testing;\nusing Microsoft.AspNetCore.Mvc.Testing;\nusing Microsoft.AspNetCore.TestHost;\n\nawait using var testClient = ConfigDirectorTesting.CreateTestClient(\n    new Dictionary\u003Cstring, object> { [\"new-checkout\"] = true });\nusing var factory = new WebApplicationFactory\u003CProgram>().WithWebHostBuilder(host =>\n    host.ConfigureTestServices(services => services.AddConfigDirectorTestClient(testClient)));\nusing var http = factory.CreateClient();\n\n(await http.GetStringAsync(\"\u002Fcheckout\")).ShouldBe(\"new\");\n\ntestClient.SetValue(\"new-checkout\", false);\n(await http.GetStringAsync(\"\u002Fcheckout\")).ShouldBe(\"classic\");\n","CheckoutTests.cs",[273,5197,5198,5210,5230,5247,5251,5271,5305,5338,5367,5386,5390,5429,5433,5455],{"__ignoreMap":319},[323,5199,5200,5202,5204,5206,5208],{"class":325,"line":326},[323,5201,450],{"class":449},[323,5203,454],{"class":453},[323,5205,548],{"class":360},[323,5207,4928],{"class":453},[323,5209,457],{"class":360},[323,5211,5212,5214,5216,5218,5220,5222,5224,5226,5228],{"class":325,"line":371},[323,5213,450],{"class":449},[323,5215,4420],{"class":453},[323,5217,548],{"class":360},[323,5219,4425],{"class":453},[323,5221,548],{"class":360},[323,5223,4430],{"class":453},[323,5225,548],{"class":360},[323,5227,4928],{"class":453},[323,5229,457],{"class":360},[323,5231,5232,5234,5236,5238,5240,5242,5245],{"class":325,"line":411},[323,5233,450],{"class":449},[323,5235,4420],{"class":453},[323,5237,548],{"class":360},[323,5239,4425],{"class":453},[323,5241,548],{"class":360},[323,5243,5244],{"class":453},"TestHost",[323,5246,457],{"class":360},[323,5248,5249],{"class":325,"line":471},[323,5250,462],{"emptyLinePlaceholder":54},[323,5252,5253,5255,5257,5259,5261,5263,5265,5267,5269],{"class":325,"line":477},[323,5254,481],{"class":480},[323,5256,485],{"class":484},[323,5258,489],{"class":488},[323,5260,4945],{"class":329},[323,5262,495],{"class":480},[323,5264,4950],{"class":545},[323,5266,548],{"class":360},[323,5268,4955],{"class":551},[323,5270,1824],{"class":360},[323,5272,5273,5275,5277,5279,5281,5283,5285,5287,5289,5291,5293,5295,5297,5299,5301,5303],{"class":325,"line":517},[323,5274,2450],{"class":480},[323,5276,4964],{"class":329},[323,5278,361],{"class":360},[323,5280,1359],{"class":480},[323,5282,685],{"class":360},[323,5284,4973],{"class":480},[323,5286,1851],{"class":360},[323,5288,710],{"class":360},[323,5290,2498],{"class":360},[323,5292,388],{"class":387},[323,5294,1747],{"class":332},[323,5296,388],{"class":387},[323,5298,2309],{"class":360},[323,5300,495],{"class":480},[323,5302,4992],{"class":1754},[323,5304,5013],{"class":360},[323,5306,5307,5309,5311,5314,5316,5318,5321,5323,5326,5328,5331,5333,5336],{"class":325,"line":522},[323,5308,450],{"class":484},[323,5310,489],{"class":488},[323,5312,5313],{"class":329}," factory",[323,5315,495],{"class":480},[323,5317,498],{"class":480},[323,5319,5320],{"class":329}," WebApplicationFactory",[323,5322,361],{"class":360},[323,5324,5325],{"class":329},"Program",[323,5327,3187],{"class":360},[323,5329,5330],{"class":551},"WithWebHostBuilder",[323,5332,504],{"class":360},[323,5334,5335],{"class":329},"host",[323,5337,1344],{"class":480},[323,5339,5340,5343,5345,5348,5350,5352,5354,5356,5358,5360,5362,5364],{"class":325,"line":528},[323,5341,5342],{"class":545},"    host",[323,5344,548],{"class":360},[323,5346,5347],{"class":551},"ConfigureTestServices",[323,5349,504],{"class":360},[323,5351,3053],{"class":329},[323,5353,3603],{"class":480},[323,5355,3112],{"class":545},[323,5357,548],{"class":360},[323,5359,3690],{"class":551},[323,5361,504],{"class":360},[323,5363,5032],{"class":545},[323,5365,5366],{"class":360},")));\n",[323,5368,5369,5371,5373,5375,5377,5379,5381,5384],{"class":325,"line":534},[323,5370,450],{"class":484},[323,5372,489],{"class":488},[323,5374,4296],{"class":329},[323,5376,495],{"class":480},[323,5378,5313],{"class":545},[323,5380,548],{"class":360},[323,5382,5383],{"class":551},"CreateClient",[323,5385,555],{"class":360},[323,5387,5388],{"class":325,"line":540},[323,5389,462],{"emptyLinePlaceholder":54},[323,5391,5392,5394,5396,5398,5400,5403,5405,5407,5410,5412,5415,5418,5420,5422,5425,5427],{"class":325,"line":1156},[323,5393,504],{"class":360},[323,5395,481],{"class":480},[323,5397,4296],{"class":545},[323,5399,548],{"class":360},[323,5401,5402],{"class":551},"GetStringAsync",[323,5404,504],{"class":360},[323,5406,388],{"class":387},[323,5408,5409],{"class":332},"\u002Fcheckout",[323,5411,388],{"class":387},[323,5413,5414],{"class":360},")).",[323,5416,5417],{"class":551},"ShouldBe",[323,5419,504],{"class":360},[323,5421,388],{"class":387},[323,5423,5424],{"class":332},"new",[323,5426,388],{"class":387},[323,5428,514],{"class":360},[323,5430,5431],{"class":325,"line":1837},[323,5432,462],{"emptyLinePlaceholder":54},[323,5434,5435,5437,5439,5441,5443,5445,5447,5449,5451,5453],{"class":325,"line":1845},[323,5436,5032],{"class":545},[323,5438,548],{"class":360},[323,5440,5099],{"class":551},[323,5442,504],{"class":360},[323,5444,388],{"class":387},[323,5446,1747],{"class":332},[323,5448,388],{"class":387},[323,5450,685],{"class":360},[323,5452,1755],{"class":1754},[323,5454,514],{"class":360},[323,5456,5457,5459,5461,5463,5465,5467,5469,5471,5473,5475,5477,5479,5481,5483,5486,5488],{"class":325,"line":1882},[323,5458,504],{"class":360},[323,5460,481],{"class":480},[323,5462,4296],{"class":545},[323,5464,548],{"class":360},[323,5466,5402],{"class":551},[323,5468,504],{"class":360},[323,5470,388],{"class":387},[323,5472,5409],{"class":332},[323,5474,388],{"class":387},[323,5476,5414],{"class":360},[323,5478,5417],{"class":551},[323,5480,504],{"class":360},[323,5482,388],{"class":387},[323,5484,5485],{"class":332},"classic",[323,5487,388],{"class":387},[323,5489,514],{"class":360},[266,5491,5492,5494,5495,5497,5498,5500,5501,5503,5504,5506,5507,5509,5510,276,5513,5515,5516,5518,5519,5522,5523,5526,5527,5530,5531,5533],{},[273,5493,3690],{}," removes every ",[273,5496,3047],{}," registration already in the collection and registers ",[273,5499,5141],{}," as an instance, so it works from ",[273,5502,5347],{},", which runs after the application's own ",[273,5505,3383],{},". The container never disposes an instance registration; the test owns the test client and disposes it. A placeholder SDK key is supplied when none is configured, so the startup validation of the key passes, and the application's startup initialization stays in place: the host calls ",[273,5508,552],{}," as in production, which completes at once with the stored values. With ",[273,5511,5512],{},"FailInitialization",[273,5514,3752],{},", host startup throws ",[273,5517,4050],{},", as it would in production. With ",[273,5520,5521],{},"HoldInitialization",", host startup waits until ",[273,5524,5525],{},"CompleteInitialization"," or the client's timeout; ",[273,5528,5529],{},"WebApplicationFactory.CreateClient()"," blocks on host startup, so call ",[273,5532,5525],{}," from another task.",[266,5535,5536,5537,5540,5541,5543,5544,276,5546,5548,5549,5551,5552,548],{},"Because the test client is built outside the container, it does not see the application's configuration: ",[273,5538,5539],{},"ConfigDirector:Connection:Timeout",", the host's ",[273,5542,781],{},", and the ",[273,5545,3722],{},[273,5547,3735],{}," metadata. Pass the timeout and logger factory to ",[273,5550,4955],{}," through ",[273,5553,5554],{},"TestClientOptions",[266,5556,5557,5558,5561,5562,5565,5566,5569],{},"A ",[273,5559,5560],{},"WebApplicationFactory"," shared by a test class through ",[273,5563,5564],{},"IClassFixture"," shares one test client across its tests. Keep the test client with the factory, register it once, and call ",[273,5567,5568],{},"ReplaceValues"," in each test's setup: it resets the values and disarms any armed hold or failure.",[313,5571,5573],{"className":439,"code":5572,"filename":5195,"language":442,"meta":319,"style":319},"public sealed class CheckoutTests : IClassFixture\u003CCheckoutTests.Factory>\n{\n    private readonly Factory _factory;\n\n    public CheckoutTests(Factory factory)\n    {\n        _factory = factory;\n        _factory.TestClient.ReplaceValues(new Dictionary\u003Cstring, object> { [\"new-checkout\"] = true });\n    }\n\n    public sealed class Factory : WebApplicationFactory\u003CProgram>\n    {\n        public TestClient TestClient { get; } = ConfigDirectorTesting.CreateTestClient();\n\n        protected override void ConfigureWebHost(IWebHostBuilder builder) =>\n            builder.ConfigureTestServices(services => services.AddConfigDirectorTestClient(TestClient));\n\n        public override async ValueTask DisposeAsync()\n        {\n            await base.DisposeAsync();\n            await TestClient.DisposeAsync();\n        }\n    }\n}\n",[273,5574,5575,5603,5607,5621,5625,5639,5643,5654,5701,5705,5709,5729,5733,5761,5765,5790,5817,5821,5838,5842,5859,5872,5878,5883],{"__ignoreMap":319},[323,5576,5577,5579,5581,5583,5586,5588,5591,5593,5596,5598,5601],{"class":325,"line":326},[323,5578,2127],{"class":2126},[323,5580,2130],{"class":2126},[323,5582,4474],{"class":488},[323,5584,5585],{"class":329}," CheckoutTests",[323,5587,4480],{"class":360},[323,5589,5590],{"class":329}," IClassFixture",[323,5592,361],{"class":360},[323,5594,5595],{"class":329},"CheckoutTests",[323,5597,548],{"class":360},[323,5599,5600],{"class":329},"Factory",[323,5602,368],{"class":360},[323,5604,5605],{"class":325,"line":371},[323,5606,695],{"class":360},[323,5608,5609,5611,5613,5616,5619],{"class":325,"line":411},[323,5610,4492],{"class":2126},[323,5612,4495],{"class":2126},[323,5614,5615],{"class":329}," Factory",[323,5617,5618],{"class":329}," _factory",[323,5620,457],{"class":360},[323,5622,5623],{"class":325,"line":471},[323,5624,462],{"emptyLinePlaceholder":54},[323,5626,5627,5629,5631,5633,5635,5637],{"class":325,"line":477},[323,5628,2145],{"class":2126},[323,5630,5585],{"class":551},[323,5632,504],{"class":360},[323,5634,5600],{"class":329},[323,5636,5313],{"class":329},[323,5638,4542],{"class":360},[323,5640,5641],{"class":325,"line":517},[323,5642,1089],{"class":360},[323,5644,5645,5648,5650,5652],{"class":325,"line":522},[323,5646,5647],{"class":545},"        _factory ",[323,5649,384],{"class":480},[323,5651,5313],{"class":545},[323,5653,457],{"class":360},[323,5655,5656,5659,5661,5663,5665,5667,5669,5671,5673,5675,5677,5679,5681,5683,5685,5687,5689,5691,5693,5695,5697,5699],{"class":325,"line":528},[323,5657,5658],{"class":545},"        _factory",[323,5660,548],{"class":360},[323,5662,5154],{"class":545},[323,5664,548],{"class":360},[323,5666,5568],{"class":551},[323,5668,504],{"class":360},[323,5670,5424],{"class":480},[323,5672,4964],{"class":329},[323,5674,361],{"class":360},[323,5676,1359],{"class":480},[323,5678,685],{"class":360},[323,5680,4973],{"class":480},[323,5682,1851],{"class":360},[323,5684,710],{"class":360},[323,5686,2498],{"class":360},[323,5688,388],{"class":387},[323,5690,1747],{"class":332},[323,5692,388],{"class":387},[323,5694,2309],{"class":360},[323,5696,495],{"class":480},[323,5698,4992],{"class":1754},[323,5700,5013],{"class":360},[323,5702,5703],{"class":325,"line":534},[323,5704,910],{"class":360},[323,5706,5707],{"class":325,"line":540},[323,5708,462],{"emptyLinePlaceholder":54},[323,5710,5711,5713,5715,5717,5719,5721,5723,5725,5727],{"class":325,"line":1156},[323,5712,2145],{"class":2126},[323,5714,2130],{"class":2126},[323,5716,4474],{"class":488},[323,5718,5615],{"class":329},[323,5720,4480],{"class":360},[323,5722,5320],{"class":329},[323,5724,361],{"class":360},[323,5726,5325],{"class":329},[323,5728,368],{"class":360},[323,5730,5731],{"class":325,"line":1837},[323,5732,1089],{"class":360},[323,5734,5735,5738,5741,5743,5745,5747,5749,5751,5753,5755,5757,5759],{"class":325,"line":1845},[323,5736,5737],{"class":2126},"        public",[323,5739,5740],{"class":329}," TestClient",[323,5742,5740],{"class":329},[323,5744,710],{"class":360},[323,5746,2156],{"class":488},[323,5748,1424],{"class":360},[323,5750,2166],{"class":360},[323,5752,495],{"class":480},[323,5754,4950],{"class":545},[323,5756,548],{"class":360},[323,5758,4955],{"class":551},[323,5760,555],{"class":360},[323,5762,5763],{"class":325,"line":1882},[323,5764,462],{"emptyLinePlaceholder":54},[323,5766,5767,5770,5773,5776,5779,5781,5784,5786,5788],{"class":325,"line":1887},[323,5768,5769],{"class":2126},"        protected",[323,5771,5772],{"class":2126}," override",[323,5774,5775],{"class":480}," void",[323,5777,5778],{"class":551}," ConfigureWebHost",[323,5780,504],{"class":360},[323,5782,5783],{"class":329},"IWebHostBuilder",[323,5785,3145],{"class":329},[323,5787,1341],{"class":360},[323,5789,1344],{"class":480},[323,5791,5792,5795,5797,5799,5801,5803,5805,5807,5809,5811,5813,5815],{"class":325,"line":1893},[323,5793,5794],{"class":545},"            builder",[323,5796,548],{"class":360},[323,5798,5347],{"class":551},[323,5800,504],{"class":360},[323,5802,3053],{"class":329},[323,5804,3603],{"class":480},[323,5806,3112],{"class":545},[323,5808,548],{"class":360},[323,5810,3690],{"class":551},[323,5812,504],{"class":360},[323,5814,5154],{"class":545},[323,5816,1385],{"class":360},[323,5818,5819],{"class":325,"line":3198},[323,5820,462],{"emptyLinePlaceholder":54},[323,5822,5823,5825,5827,5830,5833,5836],{"class":325,"line":4589},[323,5824,5737],{"class":2126},[323,5826,5772],{"class":2126},[323,5828,5829],{"class":2126}," async",[323,5831,5832],{"class":329}," ValueTask",[323,5834,5835],{"class":551}," DisposeAsync",[323,5837,4265],{"class":360},[323,5839,5840],{"class":325,"line":4633},[323,5841,3102],{"class":360},[323,5843,5845,5848,5852,5854,5857],{"class":325,"line":5844},20,[323,5846,5847],{"class":480},"            await",[323,5849,5851],{"class":5850},"s_hVV"," base",[323,5853,548],{"class":360},[323,5855,5856],{"class":551},"DisposeAsync",[323,5858,555],{"class":360},[323,5860,5862,5864,5866,5868,5870],{"class":325,"line":5861},21,[323,5863,5847],{"class":480},[323,5865,5740],{"class":545},[323,5867,548],{"class":360},[323,5869,5856],{"class":551},[323,5871,555],{"class":360},[323,5873,5875],{"class":325,"line":5874},22,[323,5876,5877],{"class":360},"        }\n",[323,5879,5881],{"class":325,"line":5880},23,[323,5882,910],{"class":360},[323,5884,5886],{"class":325,"line":5885},24,[323,5887,920],{"class":360},[599,5889,5891],{"id":5890},"values","Values",[266,5893,5894,1371,5896,3781,5898,5900,5901,5904,5905,4863,5908,5911,5912,1371,5914,5917,5918,5921,5922,5924,5925,945,5927,5930,5931,5933,5934,5937,5938,5940,5941,5944,5945,945,5948,5951,5952,5954],{},[273,5895,4955],{},[273,5897,5099],{},[273,5899,5568],{}," take native values, and the config type follows from each value's runtime type: a ",[273,5902,5903],{},"bool","; an integral type from ",[273,5906,5907],{},"sbyte",[273,5909,5910],{},"long"," (an integer config); a ",[273,5913,1991],{},[273,5915,5916],{},"double",", or ",[273,5919,5920],{},"decimal"," (a float config); a ",[273,5923,1359],{},"; or a dictionary with string keys, a list, or a ",[273,5926,1791],{},[273,5928,5929],{},"JsonNode"," holding an object or an array (a JSON config). A ",[273,5932,1359],{}," is always a string config, so JSON text meant as a JSON config is given as ",[273,5935,5936],{},"JsonNode.Parse(text)",". Every value is served as an unconditional config, so every context receives the same value; a test that needs different values per context is written as one test per value. A ",[273,5939,1527],{}," value throws ",[273,5942,5943],{},"ArgumentNullException","; an empty key, a non-finite number, an unsupported type such as ",[273,5946,5947],{},"BigInteger",[273,5949,5950],{},"DateTime",", a dictionary with non-string keys, or JSON contents that cannot be encoded throw ",[273,5953,626],{},"; in every case nothing changes.",[266,5956,5957,5958,5961,5962,5964,5965,5968,5969,5971],{},"Reads behave as they do in production: ",[273,5959,5960],{},"SetValue(\"k\", true)"," read as a string returns the in-code default value with the ",[273,5963,1592],{}," reason, and ",[273,5966,5967],{},"SetValue(\"k\", \"\")"," serves the in-code default value with the ",[273,5970,1598],{}," reason. JSON objects are encoded with their keys sorted.",[599,5973,5975],{"id":5974},"controls","Controls",[5977,5978,5979,5992],"table",{},[5980,5981,5982],"thead",{},[5983,5984,5985,5989],"tr",{},[5986,5987,5988],"th",{},"Control",[5986,5990,5991],{},"Effect",[5993,5994,5995,6016,6041,6051,6071,6083],"tbody",{},[5983,5996,5997,6003],{},[5998,5999,6000],"td",{},[273,6001,6002],{},"SetValue(key, value)",[5998,6004,6005,6006,6009,6010,1371,6012,6015],{},"Stores the value and, once the client is connected, delivers an update carrying only ",[273,6007,6008],{},"key",". Watches of ",[273,6011,6008],{},[273,6013,6014],{},"ConfigsUpdated"," handlers, and reads see it before the call returns.",[5983,6017,6018,6023],{},[5998,6019,6020],{},[273,6021,6022],{},"RemoveValue(key)",[5998,6024,6025,6026,6028,6029,6031,6032,6034,6035,6037,6038,548],{},"Removes the value and delivers a full update without it. Reads return the in-code default value with the ",[273,6027,1561],{}," reason, watches of ",[273,6030,6008],{}," receive the default, and ",[273,6033,6014],{}," lists ",[273,6036,6008],{}," in ",[273,6039,6040],{},"RemovedKeys",[5983,6042,6043,6048],{},[5998,6044,6045],{},[273,6046,6047],{},"ReplaceValues(values)",[5998,6049,6050],{},"Replaces every stored value, disarms any armed hold or failure, and delivers a full update. Use it to reset a test client shared across tests.",[5983,6052,6053,6058],{},[5998,6054,6055],{},[273,6056,6057],{},"HoldInitialization()",[5998,6059,6060,6061,6063,6064,945,6067,6070],{},"The next ",[273,6062,552],{}," waits until ",[273,6065,6066],{},"CompleteInitialization()",[273,6068,6069],{},"FailInitialization()",", or until the client's timeout elapses.",[5983,6072,6073,6077],{},[5998,6074,6075],{},[273,6076,6066],{},[5998,6078,6079,6080,6082],{},"Delivers the stored values to the held ",[273,6081,552],{},", on the calling thread, so the client is ready when the call returns. Called while a hold is armed but not picked up, it disarms the hold.",[5983,6084,6085,6089],{},[5998,6086,6087],{},[273,6088,6069],{},[5998,6090,6091,6092,6094,6095,6097],{},"Fails the held ",[273,6093,552],{}," the way an invalid SDK key does: it completes promptly, the client is not ready, and the error is logged. Called with no ",[273,6096,552],{}," held, it arms the next one to fail.",[266,6099,6100,6101,6103],{},"After a failed attempt, the next ",[273,6102,552],{}," succeeds and delivers the values stored in the meantime.",[313,6105,6107],{"className":439,"code":6106,"filename":4915,"language":442,"meta":319,"style":319},"await using var testClient = ConfigDirectorTesting.CreateTestClient(\n    new Dictionary\u003Cstring, object> { [\"new-checkout\"] = true },\n    new TestClientOptions { Timeout = TimeSpan.FromMilliseconds(500) });\ntestClient.FailInitialization();\n\nawait testClient.Client.InitializeAsync();\n\ntestClient.Client.IsReady.ShouldBeFalse();\nservice.IsNewCheckoutEnabled(\"user-123\").ShouldBeFalse();\n",[273,6108,6109,6129,6163,6193,6203,6207,6223,6227,6245],{"__ignoreMap":319},[323,6110,6111,6113,6115,6117,6119,6121,6123,6125,6127],{"class":325,"line":326},[323,6112,481],{"class":480},[323,6114,485],{"class":484},[323,6116,489],{"class":488},[323,6118,4945],{"class":329},[323,6120,495],{"class":480},[323,6122,4950],{"class":545},[323,6124,548],{"class":360},[323,6126,4955],{"class":551},[323,6128,1824],{"class":360},[323,6130,6131,6133,6135,6137,6139,6141,6143,6145,6147,6149,6151,6153,6155,6157,6159,6161],{"class":325,"line":371},[323,6132,2450],{"class":480},[323,6134,4964],{"class":329},[323,6136,361],{"class":360},[323,6138,1359],{"class":480},[323,6140,685],{"class":360},[323,6142,4973],{"class":480},[323,6144,1851],{"class":360},[323,6146,710],{"class":360},[323,6148,2498],{"class":360},[323,6150,388],{"class":387},[323,6152,1747],{"class":332},[323,6154,388],{"class":387},[323,6156,2309],{"class":360},[323,6158,495],{"class":480},[323,6160,4992],{"class":1754},[323,6162,740],{"class":360},[323,6164,6165,6167,6170,6172,6175,6177,6179,6181,6184,6186,6189,6191],{"class":325,"line":411},[323,6166,2450],{"class":480},[323,6168,6169],{"class":329}," TestClientOptions",[323,6171,710],{"class":360},[323,6173,6174],{"class":545}," Timeout ",[323,6176,384],{"class":480},[323,6178,1115],{"class":545},[323,6180,548],{"class":360},[323,6182,6183],{"class":551},"FromMilliseconds",[323,6185,504],{"class":360},[323,6187,6188],{"class":346},"500",[323,6190,1341],{"class":360},[323,6192,5013],{"class":360},[323,6194,6195,6197,6199,6201],{"class":325,"line":471},[323,6196,5032],{"class":545},[323,6198,548],{"class":360},[323,6200,5512],{"class":551},[323,6202,555],{"class":360},[323,6204,6205],{"class":325,"line":477},[323,6206,462],{"emptyLinePlaceholder":54},[323,6208,6209,6211,6213,6215,6217,6219,6221],{"class":325,"line":517},[323,6210,481],{"class":480},[323,6212,4945],{"class":545},[323,6214,548],{"class":360},[323,6216,5037],{"class":545},[323,6218,548],{"class":360},[323,6220,552],{"class":551},[323,6222,555],{"class":360},[323,6224,6225],{"class":325,"line":522},[323,6226,462],{"emptyLinePlaceholder":54},[323,6228,6229,6231,6233,6235,6237,6239,6241,6243],{"class":325,"line":528},[323,6230,5032],{"class":545},[323,6232,548],{"class":360},[323,6234,5037],{"class":545},[323,6236,548],{"class":360},[323,6238,570],{"class":545},[323,6240,548],{"class":360},[323,6242,5134],{"class":551},[323,6244,555],{"class":360},[323,6246,6247,6249,6251,6253,6255,6257,6259,6261,6263,6265],{"class":325,"line":534},[323,6248,5064],{"class":545},[323,6250,548],{"class":360},[323,6252,5069],{"class":551},[323,6254,504],{"class":360},[323,6256,388],{"class":387},[323,6258,5076],{"class":332},[323,6260,388],{"class":387},[323,6262,5081],{"class":360},[323,6264,5134],{"class":551},[323,6266,555],{"class":360},[599,6268,6269],{"id":3600},"Options",[266,6271,6272,6275,6276,6278,6279,6281,6282,6284,6285,6287],{},[273,6273,6274],{},"CreateTestClient(values, new TestClientOptions { ... })"," takes ",[273,6277,997],{}," (the client's connection timeout, which bounds how long a held ",[273,6280,552],{}," waits; defaults to the SDK's production timeout) and ",[273,6283,767],{}," (defaults to the SDK's default, ",[273,6286,777],{},", which discards everything; pass a factory to see the client's logs).",[599,6289,6291],{"id":6290},"what-to-expect","What to expect",[930,6293,6294,6306,6321,6330,6338,6341],{},[427,6295,6296,6297,6299,6300,6302,6303,548],{},"The first update is delivered while ",[273,6298,552],{}," connects, so watches registered before it run before it completes, and ",[273,6301,6014],{}," fires before ",[273,6304,6305],{},"ClientReady",[427,6307,6308,6309,1371,6311,1371,6314,1371,6316,5917,6318,6320],{},"Watches and handlers run on the thread that calls ",[273,6310,5099],{},[273,6312,6313],{},"RemoveValue",[273,6315,5568],{},[273,6317,5525],{},[273,6319,552],{},", not on a transport thread.",[427,6322,6323,6324,6326,6327,6329],{},"A held ",[273,6325,552],{}," that times out, or that is interrupted by disposing the client, leaves the client not ready until the next ",[273,6328,552],{},", and logs the SDK's timeout warning; production streaming would keep retrying in the background.",[427,6331,6332,6333,276,6335,6337],{},"Watches fire on every update carrying their key, whether or not the value changed, as in production. ",[273,6334,6313],{},[273,6336,5568],{}," deliver a full update, so they also fire the watches of every remaining key.",[427,6339,6340],{},"An exception thrown by a watch or handler is caught and logged by the client, as in production, so a failed assertion inside a watch does not fail the test by itself.",[427,6342,6343,6344,6346,6347,6349,6350,6352,6353,6356],{},"After the client is disposed, ",[273,6345,570],{}," is false, reads return the in-code default value, ",[273,6348,2956],{}," returns an empty dictionary, ",[273,6351,552],{}," throws ",[273,6354,6355],{},"ObjectDisposedException",", every watch and event handler has been removed, and the test client's controls are silent no-ops.",[6358,6359,6360],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s9AJx, html code.shiki .s9AJx{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sw1J6, html code.shiki .sw1J6{--shiki-light:#F76D47;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sfCm-, html code.shiki .sfCm-{--shiki-light:#90A4AE;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sG8yY, html code.shiki .sG8yY{--shiki-light:#E2931D;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sseR_, html code.shiki .sseR_{--shiki-light:#9C3EDA;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":319,"searchDepth":371,"depth":371,"links":6362},[6363,6364,6365,6369,6374,6382,6390],{"id":263,"depth":371,"text":264},{"id":299,"depth":371,"text":300},{"id":421,"depth":371,"text":422,"children":6366},[6367,6368],{"id":601,"depth":411,"text":602},{"id":1295,"depth":411,"text":1296},{"id":1614,"depth":371,"text":1615,"children":6370},[6371,6372,6373],{"id":1999,"depth":411,"text":2000},{"id":2202,"depth":411,"text":2203},{"id":2743,"depth":411,"text":2744},{"id":2923,"depth":371,"text":2924,"children":6375},[6376,6377,6378,6379,6380,6381],{"id":2930,"depth":411,"text":570},{"id":2944,"depth":411,"text":2947},{"id":2953,"depth":411,"text":2956},{"id":2972,"depth":411,"text":2975},{"id":2981,"depth":411,"text":2984},{"id":2990,"depth":411,"text":2991},{"id":3226,"depth":371,"text":295,"children":6383},[6384,6385,6386,6387,6388,6389],{"id":3249,"depth":411,"text":3250},{"id":3337,"depth":411,"text":3338},{"id":3698,"depth":411,"text":3699},{"id":4037,"depth":411,"text":4038},{"id":4223,"depth":411,"text":4224},{"id":4658,"depth":411,"text":4659},{"id":4873,"depth":371,"text":3695,"children":6391},[6392,6393,6394,6395,6396],{"id":5161,"depth":411,"text":5162},{"id":5890,"depth":411,"text":5891},{"id":5974,"depth":411,"text":5975},{"id":3600,"depth":411,"text":6269},{"id":6290,"depth":411,"text":6291},"Evaluate configs and feature flags locally for any user context with the .NET server SDK, with updates delivered over server sent events","md",null,{"modifiedAt":6401},"2026-10-12T00:22:49.000Z",{"title":172,"icon":175},{"title":246,"description":6397},"DHDjtEewo3FXfv6Dt9hmfZA0QXgc3dMWB3xVBtLDjS0",[6406,6408],{"title":167,"path":168,"stem":169,"description":6407,"icon":170,"children":-1},"Evaluate configs and feature flags locally for any user context with the Java server SDK, with updates delivered over server sent events",{"title":177,"path":178,"stem":179,"description":6409,"icon":180,"children":-1},"Evaluate configs and feature flags locally for any user context with the Go server SDK, with updates delivered over server sent events",1791783866820]