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.
5 using System
.Collections
.Generic
;
6 using System
.Reflection
;
7 using System
.Runtime
.ExceptionServices
;
8 using System
.Runtime
.Loader
;
9 using System
.Runtime
.Versioning
;
10 using System
.Threading
;
14 public static partial class AppContext
16 private static readonly Dictionary
<string, object?> s_dataStore
= new Dictionary
<string, object?>();
17 private static Dictionary
<string, bool>? s_switches
;
18 private static string? s_defaultBaseDirectory
;
20 public static string BaseDirectory
=>
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 (string?)GetData("APP_CONTEXT_BASE_DIRECTORY") ??
24 (s_defaultBaseDirectory
??= GetBaseDirectoryCore());
26 public static string? TargetFrameworkName
=>
27 // The Target framework is not the framework that the process is actually running on.
28 // It is the value read from the TargetFrameworkAttribute on the .exe that started the process.
29 Assembly
.GetEntryAssembly()?.GetCustomAttribute
<TargetFrameworkAttribute
>()?.FrameworkName
;
31 public static object? GetData(string name
)
34 throw new ArgumentNullException(nameof(name
));
39 s_dataStore
.TryGetValue(name
, out data
);
44 public static void SetData(string name
, object? data
)
47 throw new ArgumentNullException(nameof(name
));
51 s_dataStore
[name
] = data
;
55 #pragma warning disable CS0067 // events raised by the VM
56 public static event UnhandledExceptionEventHandler
? UnhandledException
;
58 public static event System
.EventHandler
<FirstChanceExceptionEventArgs
>? FirstChanceException
;
59 #pragma warning restore CS0067
61 public static event System
.EventHandler
? ProcessExit
;
63 internal static void OnProcessExit()
65 AssemblyLoadContext
.OnProcessExit();
67 ProcessExit
?.Invoke(AppDomain
.CurrentDomain
, EventArgs
.Empty
);
71 /// Try to get the value of the switch.
73 /// <param name="switchName">The name of the switch</param>
74 /// <param name="isEnabled">A variable where to place the value of the switch</param>
75 /// <returns>A return value of true represents that the switch was set and <paramref name="isEnabled"/> contains the value of the switch</returns>
76 public static bool TryGetSwitch(string switchName
, out bool isEnabled
)
78 if (switchName
== null)
79 throw new ArgumentNullException(nameof(switchName
));
80 if (switchName
.Length
== 0)
81 throw new ArgumentException(SR
.Argument_EmptyName
, nameof(switchName
));
83 if (s_switches
!= null)
87 if (s_switches
.TryGetValue(switchName
, out isEnabled
))
92 if (GetData(switchName
) is string value && bool.TryParse(value, out isEnabled
))
102 /// Assign a switch a value
104 /// <param name="switchName">The name of the switch</param>
105 /// <param name="isEnabled">The value to assign</param>
106 public static void SetSwitch(string switchName
, bool isEnabled
)
108 if (switchName
== null)
109 throw new ArgumentNullException(nameof(switchName
));
110 if (switchName
.Length
== 0)
111 throw new ArgumentException(SR
.Argument_EmptyName
, nameof(switchName
));
113 if (s_switches
== null)
115 // Compatibility switches are rarely used. Initialize the Dictionary lazily
116 Interlocked
.CompareExchange(ref s_switches
, new Dictionary
<string, bool>(), null);
121 s_switches
[switchName
] = isEnabled
;