3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 using System.Collections.Generic;
11 public static class AppContext
14 private enum SwitchValueState
18 HasLookedForOverride = 0x4,
19 UnknownValue = 0x8 // Has no default and could not find an override
21 private static readonly Dictionary<string, SwitchValueState> s_switchMap = new Dictionary<string, SwitchValueState>();
23 public static string BaseDirectory
26 [System.Security.SecuritySafeCritical]
30 // The value of APP_CONTEXT_BASE_DIRECTORY key has to be a string and it is not allowed to be any other type.
31 // Otherwise the caller will get invalid cast exception
32 return (string) AppDomain.CurrentDomain.GetData("APP_CONTEXT_BASE_DIRECTORY") ?? AppDomain.CurrentDomain.BaseDirectory;
36 public static string TargetFrameworkName
40 throw new NotImplementedException();
44 public static object GetData (string name)
46 throw new NotImplementedException();
53 // populate the AppContext with the default set of values
54 AppContextDefaultValues.PopulateDefaultValues();
58 /// Try to get the value of the switch.
60 /// <param name="switchName">The name of the switch</param>
61 /// <param name="isEnabled">A variable where to place the value of the switch</param>
62 /// <returns>A return value of true represents that the switch was set and <paramref name="isEnabled"/> contains the value of the switch</returns>
63 public static bool TryGetSwitch(string switchName, out bool isEnabled)
65 if (switchName == null)
66 throw new ArgumentNullException("switchName");
67 if (switchName.Length == 0)
68 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "switchName");
70 // By default, the switch is not enabled.
73 SwitchValueState switchValue;
76 if (s_switchMap.TryGetValue(switchName, out switchValue))
78 // The value is in the dictionary.
79 // There are 3 cases here:
80 // 1. The value of the switch is 'unknown'. This means that the switch name is not known to the system (either via defaults or checking overrides).
81 // Example: This is the case when, during a servicing event, a switch is added to System.Xml which ships before mscorlib. The value of the switch
82 // Will be unknown to mscorlib.dll and we want to prevent checking the overrides every time we check this switch
83 // 2. The switch has a valid value AND we have read the overrides for it
84 // Example: TryGetSwitch is called for a switch set via SetSwitch
85 // 3. The switch has the default value and we need to check for overrides
86 // Example: TryGetSwitch is called for the first time for a switch that has a default value
88 // 1. The value is unknown
89 if (switchValue == SwitchValueState.UnknownValue)
95 // We get the value of isEnabled from the value that we stored in the dictionary
96 isEnabled = (switchValue & SwitchValueState.HasTrueValue) == SwitchValueState.HasTrueValue;
98 // 2. The switch has a valid value AND we have checked for overrides
99 if ((switchValue & SwitchValueState.HasLookedForOverride) == SwitchValueState.HasLookedForOverride)
104 // 3. The switch has a valid value, but we need to check for overrides.
105 // Regardless of whether or not the switch has an override, we need to update the value to reflect
106 // the fact that we checked for overrides.
108 if (AppContextDefaultValues.TryGetSwitchOverride(switchName, out overrideValue))
110 // we found an override!
111 isEnabled = overrideValue;
114 // Update the switch in the dictionary to mark it as 'checked for override'
115 s_switchMap[switchName] = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue)
116 | SwitchValueState.HasLookedForOverride;
122 // The value is NOT in the dictionary
123 // In this case we need to see if we have an override defined for the value.
124 // There are 2 cases:
125 // 1. The value has an override specified. In this case we need to add the value to the dictionary
126 // and mark it as checked for overrides
127 // Example: In a servicing event, System.Xml introduces a switch and an override is specified.
128 // The value is not found in mscorlib (as System.Xml ships independent of mscorlib)
129 // 2. The value does not have an override specified
130 // In this case, we want to capture the fact that we looked for a value and found nothing by adding
131 // an entry in the dictionary with the 'sentinel' value of 'SwitchValueState.UnknownValue'.
132 // Example: This will prevent us from trying to find overrides for values that we don't have in the dictionary
134 // 1. The value has an override specified.
136 if (AppContextDefaultValues.TryGetSwitchOverride(switchName, out overrideValue))
138 isEnabled = overrideValue;
140 // Update the switch in the dictionary to mark it as 'checked for override'
141 s_switchMap[switchName] = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue)
142 | SwitchValueState.HasLookedForOverride;
147 // 2. The value does not have an override.
148 s_switchMap[switchName] = SwitchValueState.UnknownValue;
151 return false; // we did not find a value for the switch
155 /// Assign a switch a value
157 /// <param name="switchName">The name of the switch</param>
158 /// <param name="isEnabled">The value to assign</param>
159 public static void SetSwitch(string switchName, bool isEnabled)
161 if (switchName == null)
162 throw new ArgumentNullException("switchName");
163 if (switchName.Length == 0)
164 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "switchName");
166 SwitchValueState switchValue = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue)
167 | SwitchValueState.HasLookedForOverride;
170 // Store the new value and the fact that we checked in the dictionary
171 s_switchMap[switchName] = switchValue;
176 /// This method is going to be called from the AppContextDefaultValues class when setting up the
177 /// default values for the switches. !!!! This method is called during the static constructor so it does not
178 /// take a lock !!!! If you are planning to use this outside of that, please ensure proper locking.
180 internal static void DefineSwitchDefault(string switchName, bool isEnabled)
182 s_switchMap[switchName] = isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue;