AppContext Class
Definition
Important
Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
Provides members for setting and retrieving data about an application's context.
public ref class AppContext abstract sealed
public static class AppContext
type AppContext = class
Public Class AppContext
- Inheritance
-
AppContext
Remarks
The AppContext class enables library writers to provide a uniform opt-out mechanism for new functionality for their users. It establishes a loosely coupled contract between components in order to communicate an opt-out request. This capability is typically important when a change is made to existing functionality. Conversely, there is already an implicit opt-in for new functionality.
AppContext for library developers
Libraries use the AppContext class to define and expose compatibility switches, while library users can set those switches to affect the library behavior. By default, libraries provide the new functionality, and they only alter it (that is, they provide the previous functionality) if the switch is set. This allows libraries to provide new behavior for an existing API while continuing to support callers who depend on the previous behavior.
Define the switch name
The most common way to allow consumers of your library to opt out of a change of behavior is to define a named switch. Its value element is a name/value pair that consists of the name of a switch and its Boolean value. By default, the switch is always implicitly false, which provides the new behavior (and makes the new behavior opt-in by default). Setting the switch to true enables it, which provides the legacy behavior. Explicitly setting the switch to false also provides the new behavior.
It's beneficial to use a consistent format for switch names, since they're a formal contract exposed by a library. The following are two obvious formats:
- Switch.namespace.switchname
- Switch.library.switchname
Once you define and document the switch, callers can use it by calling the AppContext.SetSwitch(String, Boolean) method programmatically.
Check the setting
You can check if a consumer has declared the value of the switch and act appropriately by calling the AppContext.TryGetSwitch method. The method returns true if the switchName argument is found, and its isEnabled argument indicates the value of the switch. Otherwise, the method returns false.
Example
The following example illustrates the use of the AppContext class to allow the customer to choose the original behavior of a library method. The following is version 1.0 of a library named StringLibrary. It defines a SubstringStartsAt method that performs an ordinal comparison to determine the starting index of a substring within a larger string.
using System;
using System.Reflection;
[assembly: AssemblyVersion("1.0.0.0")]
public static class StringLibrary1
{
public static int SubstringStartsAt(string fullString, string substr)
{
return fullString.IndexOf(substr, StringComparison.Ordinal);
}
}
open System
open System.Reflection
[<assembly: AssemblyVersion("1.0.0.0")>]
do ()
module StringLibrary =
let substringStartsAt (fullString: string) (substr: string) =
fullString.IndexOf(substr, StringComparison.Ordinal)
Imports System.Reflection
<Assembly: AssemblyVersion("1.0.0.0")>
Public Class StringLibrary
Public Shared Function SubstringStartsAt(fullString As String, substr As String) As Integer
Return fullString.IndexOf(substr, StringComparison.Ordinal)
End Function
End Class
The following example then uses the library to find the starting index of the substring "archæ" in "The archaeologist". Because the method performs an ordinal comparison, the substring cannot be found.
using System;
public class Example1
{
public static void Main()
{
string value = "The archaeologist";
string substring = "archæ";
int position = StringLibrary1.SubstringStartsAt(value, substring);
if (position >= 0)
Console.WriteLine($"'{substring}' found in '{value}' starting at position {position}");
else
Console.WriteLine($"'{substring}' not found in '{value}'");
}
}
// The example displays the following output:
// 'archæ' not found in 'The archaeologist'
let value = "The archaeologist"
let substring = "archæ"
let position =
StringLibrary.substringStartsAt value substring
if position >= 0 then
printfn $"'{substring}' found in '{value}' starting at position {position}"
else
printfn $"'{substring}' not found in '{value}'"
// The example displays the following output:
// 'archæ' not found in 'The archaeologist'
Public Module Example4
Public Sub Main()
Dim value As String = "The archaeologist"
Dim substring As String = "archæ"
Dim position As Integer = StringLibrary.SubstringStartsAt(value, substring)
If position >= 0 Then
Console.WriteLine("'{0}' found in '{1}' starting at position {2}",
substring, value, position)
Else
Console.WriteLine("'{0}' not found in '{1}'", substring, value)
End If
End Sub
End Module
' The example displays the following output:
' 'archæ' not found in 'The archaeologist'
Version 2.0 of the library, however, changes the SubstringStartsAt method to use culture-sensitive comparison.
using System;
using System.Reflection;
[assembly: AssemblyVersion("2.0.0.0")]
public static class StringLibrary2
{
public static int SubstringStartsAt(string fullString, string substr)
{
return fullString.IndexOf(substr, StringComparison.CurrentCulture);
}
}
open System
open System.Reflection
[<assembly: AssemblyVersion("2.0.0.0")>]
do ()
module StringLibrary =
let substringStartsAt (fullString: string) (substr: string) =
fullString.IndexOf(substr, StringComparison.CurrentCulture)
Imports System.Reflection
<Assembly: AssemblyVersion("2.0.0.0")>
Public Class StringLibrary
Public Shared Function SubstringStartsAt(fullString As String, substr As String) As Integer
Return fullString.IndexOf(substr, StringComparison.CurrentCulture)
End Function
End Class
When the app is recompiled to run against the new version of the library, it now reports that the substring "archæ" is found at index 4 in "The archaeologist".
using System;
public class Example2
{
public static void Main()
{
string value = "The archaeologist";
string substring = "archæ";
int position = StringLibrary2.SubstringStartsAt(value, substring);
if (position >= 0)
Console.WriteLine($"'{substring}' found in '{value}' starting at position {position}");
else
Console.WriteLine($"'{substring}' not found in '{value}'");
}
}
// The example displays the following output:
// 'archæ' found in 'The archaeologist' starting at position 4
let value = "The archaeologist"
let substring = "archæ"
let position =
StringLibrary.substringStartsAt value substring
if position >= 0 then
printfn $"'{substring}' found in '{value}' starting at position {position}"
else
printfn $"'{substring}' not found in '{value}'"
// The example displays the following output:
// 'archæ' found in 'The archaeologist' starting at position 4
Public Module Example6
Public Sub Main()
Dim value As String = "The archaeologist"
Dim substring As String = "archæ"
Dim position As Integer = StringLibrary.SubstringStartsAt(value, substring)
If position >= 0 Then
Console.WriteLine("'{0}' found in '{1}' starting at position {2}",
substring, value, position)
Else
Console.WriteLine("'{0}' not found in '{1}'", substring, value)
End If
End Sub
End Module
' The example displays the following output:
' 'archæ' found in 'The archaeologist' starting at position 4
This change can be prevented from breaking the applications that depend on the original behavior by defining a switch. In this case, the switch is named StringLibrary.DoNotUseCultureSensitiveComparison. Its default value, false, indicates that the library should perform its version 2.0 culture-sensitive comparison. true indicates that the library should perform its version 1.0 ordinal comparison. A slight modification of the previous code allows the library consumer to set the switch to determine the kind of comparison the method performs.
using System;
using System.Reflection;
[assembly: AssemblyVersion("2.0.0.0")]
public static class StringLibrary
{
public static int SubstringStartsAt(string fullString, string substr)
{
bool flag;
if (AppContext.TryGetSwitch("StringLibrary.DoNotUseCultureSensitiveComparison", out flag) && flag == true)
return fullString.IndexOf(substr, StringComparison.Ordinal);
else
return fullString.IndexOf(substr, StringComparison.CurrentCulture);
}
}
open System
open System.Reflection
[<assembly: AssemblyVersion("2.0.0.0")>]
do ()
AppContext.SetSwitch("StringLibrary.DoNotUseCultureSensitiveComparison",true)
module StringLibrary =
let substringStartsAt (fullString: string) (substr: string) =
match AppContext.TryGetSwitch "StringLibrary.DoNotUseCultureSensitiveComparison" with
| true, true -> fullString.IndexOf(substr, StringComparison.Ordinal)
| _ -> fullString.IndexOf(substr, StringComparison.CurrentCulture)
Imports System.Reflection
<Assembly: AssemblyVersion("2.0.0.0")>
Public Class StringLibrary
Public Shared Function SubstringStartsAt(fullString As String, substr As String) As Integer
Dim flag As Boolean
If AppContext.TryGetSwitch("StringLibrary.DoNotUseCultureSensitiveComparison", flag) AndAlso flag = True Then
Return fullString.IndexOf(substr, StringComparison.Ordinal)
Else
Return fullString.IndexOf(substr, StringComparison.CurrentCulture)
End If
End Function
End Class
AppContext for library consumers
If you're the consumer of a library, the AppContext class allows you to take advantage of a library or library method's opt-out mechanism for new functionality. Individual methods of the class library that you are calling define particular switches that enable or disable a new behavior. The value of the switch is a Boolean. If it is false, which is typically the default value, the new behavior is enabled; if it is true, the new behavior is disabled, and the member behaves as it did previously.
You can set the value of a switch by calling the AppContext.SetSwitch(String, Boolean) method in your code. The switchName argument defines the switch name, and the isEnabled property defines the value of the switch. Because AppContext is a static class, it is available on a per-application domain basis. Calling the AppContext.SetSwitch(String, Boolean) has application scope; that is, it affects only the application.
For ASP.NET Core applications, you set a switch by adding an <Add> element to the <appSettings> section of the web.config file. For example:
<appSettings>
<add key="AppContext.SetSwitch:switchName1" value="switchValue1" />
<add key="AppContext.SetSwitch:switchName2" value="switchValue2" />
</appSettings>
If you set the same switch in more than one way, the order of precedence for determining which setting overrides the others is:
- The programmatic setting.
- The setting in the web.config file (for ASP.NET Core apps).
Properties
| Name | Description |
|---|---|
| BaseDirectory |
Gets the file path of the base directory that the assembly resolver uses to probe for assemblies. |
| TargetFrameworkName |
Gets the name of the framework version targeted by the current application. |
Methods
| Name | Description |
|---|---|
| GetData(String) |
Returns the value of the named data element assigned to the current application domain. |
| SetData(String, Object) |
Sets the value of the named data element assigned to the current application domain. |
| SetSwitch(String, Boolean) |
Sets the value of a switch. |
| TryGetSwitch(String, Boolean) |
Tries to get the value of a switch. |