AppContext.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.Reflection;
  6. using System.Runtime.ExceptionServices;
  7. using System.Runtime.Loader;
  8. using System.Runtime.Versioning;
  9. using System.Threading;
  10. namespace System
  11. {
  12. public static partial class AppContext
  13. {
  14. private static readonly Dictionary<string, object> s_dataStore = new Dictionary<string, object>();
  15. private static Dictionary<string, bool> s_switches;
  16. private static string s_defaultBaseDirectory;
  17. public static string BaseDirectory
  18. {
  19. get
  20. {
  21. // The value of APP_CONTEXT_BASE_DIRECTORY key has to be a string and it is not allowed to be any other type.
  22. // Otherwise the caller will get invalid cast exception
  23. return (string)GetData("APP_CONTEXT_BASE_DIRECTORY") ??
  24. (s_defaultBaseDirectory ?? (s_defaultBaseDirectory = GetBaseDirectoryCore()));
  25. }
  26. }
  27. public static string TargetFrameworkName
  28. {
  29. get
  30. {
  31. // The Target framework is not the framework that the process is actually running on.
  32. // It is the value read from the TargetFrameworkAttribute on the .exe that started the process.
  33. return Assembly.GetEntryAssembly()?.GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName;
  34. }
  35. }
  36. public static object GetData(string name)
  37. {
  38. if (name == null)
  39. throw new ArgumentNullException(nameof(name));
  40. object data;
  41. lock (s_dataStore)
  42. {
  43. s_dataStore.TryGetValue(name, out data);
  44. }
  45. return data;
  46. }
  47. public static void SetData(string name, object data)
  48. {
  49. if (name == null)
  50. throw new ArgumentNullException(nameof(name));
  51. lock (s_dataStore)
  52. {
  53. s_dataStore[name] = data;
  54. }
  55. }
  56. #pragma warning disable CS0067 // events raised by the VM
  57. public static event UnhandledExceptionEventHandler UnhandledException;
  58. public static event System.EventHandler<FirstChanceExceptionEventArgs> FirstChanceException;
  59. #pragma warning restore CS0067
  60. public static event System.EventHandler ProcessExit;
  61. internal static void OnProcessExit()
  62. {
  63. AssemblyLoadContext.OnProcessExit();
  64. ProcessExit?.Invoke(null /* AppDomain */, EventArgs.Empty);
  65. }
  66. /// <summary>
  67. /// Try to get the value of the switch.
  68. /// </summary>
  69. /// <param name="switchName">The name of the switch</param>
  70. /// <param name="isEnabled">A variable where to place the value of the switch</param>
  71. /// <returns>A return value of true represents that the switch was set and <paramref name="isEnabled"/> contains the value of the switch</returns>
  72. public static bool TryGetSwitch(string switchName, out bool isEnabled)
  73. {
  74. if (switchName == null)
  75. throw new ArgumentNullException(nameof(switchName));
  76. if (switchName.Length == 0)
  77. throw new ArgumentException(SR.Argument_EmptyName, nameof(switchName));
  78. if (s_switches != null)
  79. {
  80. lock (s_switches)
  81. {
  82. if (s_switches.TryGetValue(switchName, out isEnabled))
  83. return true;
  84. }
  85. }
  86. if (GetData(switchName) is string value && bool.TryParse(value, out isEnabled))
  87. {
  88. return true;
  89. }
  90. isEnabled = false;
  91. return false;
  92. }
  93. /// <summary>
  94. /// Assign a switch a value
  95. /// </summary>
  96. /// <param name="switchName">The name of the switch</param>
  97. /// <param name="isEnabled">The value to assign</param>
  98. public static void SetSwitch(string switchName, bool isEnabled)
  99. {
  100. if (switchName == null)
  101. throw new ArgumentNullException(nameof(switchName));
  102. if (switchName.Length == 0)
  103. throw new ArgumentException(SR.Argument_EmptyName, nameof(switchName));
  104. if (s_switches == null)
  105. {
  106. // Compatibility switches are rarely used. Initialize the Dictionary lazily
  107. Interlocked.CompareExchange(ref s_switches, new Dictionary<string, bool>(), null);
  108. }
  109. lock (s_switches)
  110. {
  111. s_switches[switchName] = isEnabled;
  112. }
  113. }
  114. }
  115. }