Atc 4.1.0
dotnet add package Atc --version 4.1.0
NuGet\Install-Package Atc -Version 4.1.0
<PackageReference Include="Atc" Version="4.1.0" />
<PackageVersion Include="Atc" Version="4.1.0" />
<PackageReference Include="Atc" />
paket add Atc --version 4.1.0
#r "nuget: Atc, 4.1.0"
#:package Atc@4.1.0
#addin nuget:?package=Atc&version=4.1.0
#tool nuget:?package=Atc&version=4.1.0
Atc
Target Frameworks: netstandard2.0, net10.0
The foundation library for .NET development, providing a comprehensive collection of common utilities, extension methods, and helpers. Multi-targeting ensures compatibility with a wide range of .NET applications, from .NET Framework 4.7.2+ to the latest .NET versions.
Why Use This Library?
Atc eliminates boilerplate code and provides battle-tested implementations for common tasks. Instead of writing the same utility code in every project, Atc provides:
- Rich Extension Methods: Extensions for all common .NET types (String, DateTime, Enum, Collections, etc.)
- Logging Utilities: Structured logging helpers for ILogger
- Data Structures: Specialized collections and data structures
- Serialization Helpers: JSON serialization utilities with sensible defaults
- Math & Geometry: Math operations, geospatial calculations, and coordinate systems
- Networking Helpers: Network information and IP address utilities
Perfect for:
- Reducing boilerplate in business applications
- Standardizing common operations across projects
- Improving code readability with expressive extension methods
- Building reusable libraries
Installation
dotnet add package Atc
Target Frameworks
- .NET Standard 2.0
- .NET 10.0
The library multi-targets to provide broad compatibility with:
- .NET Framework 4.7.2+
- .NET Core 2.1+
- .NET 5+
- .NET 10.0
Key Dependencies
- Microsoft.Extensions.Logging.Abstractions
- System.Text.Json
- System.ComponentModel.Annotations
- Meziantou.Polyfill (for backward compatibility)
Main Components
Extension Methods (Extensions/)
Organized by category:
- BaseTypes: String, Int, Double, Bool, Enum, DateTime, TimeSpan
- Collections: List, Dictionary, IEnumerable, Array
- Reflection: Type, Assembly, MethodInfo
- Serialization: JSON serialization helpers
- Stream: Stream and byte array operations
Logging (Logging/)
ILoggerextensions for structured loggingLogKeyValueItemfor key-value pair loggingLogItemFactoryfor creating log items
Math & Geometry (Math/)
MathEx: Extended math operations- GeoSpatial calculations and coordinates
- Cartesian and geographic coordinate systems
Helpers
NetworkInformationHelper: Network connectivity and IP address utilitiesJsonSerializerOptionsFactory: Preconfigured JSON serialization options
Data Structures
- Specialized collections
- Custom data structures for common scenarios
Resources
Localized resources for:
- English (default)
- Danish (da-DK)
- German (de-DE)
Code Documentation
Examples
ILogger examples
Using logger.LogKeyValueItems(..)
// Collect data
var logItems = new List<LogKeyValueItem>
{
new LogKeyValueItem(LogCategoryType.Error, "Key1", "Error1"),
new LogKeyValueItem(LogCategoryType.Warning, "Key2", "Warning1"),
new LogKeyValueItem(LogCategoryType.Information, "Key3", "Information1"),
LogItemFactory.CreateError("Key4", "Error2"),
LogItemFactory.CreateWarning("Key5", "Warning2"),
LogItemFactory.CreateInformation("Key6", "Information2"),
};
// Log data
logger.LogKeyValueItems(logItems);
Using logger.LogKeyValueItem(..)
// Collect data
var logItem = LogItemFactory.CreateError("Key1", "Error1");
// Log data
logger.LogKeyValueItem(LogItemFactory.CreateError(logItem));
TimeSpanExtensions examples
Using GetPrettyTime() or GetPrettyTime(decimalPrecision)
The default value for decimalPrecision is 3.
var stopwatch = Stopwatch.StartNew();
DoSomthingThatTakesLongTime();
stopwatch.Stop();
Console.WriteLine($"Running time: {stopwatch.Elapsed.GetPrettyTime()}");
Result format could look like:
Running time: 14,015 sec
Running time: 13,234 min
Running time: 12,213 hours
NetworkInformationHelper examples
Using HasConnection()
This helper method ask a external internet service (GoogleDNS ping), to see it there is connection.
bool hasConnection = NetworkInformationHelper.HasConnection()
Using GetPublicIpAddress()
This helper method ask a external internet service (ipify.org), to get the external ip address.
IPAddress? ipAddress = NetworkInformationHelper.GetPublicIpAddress()
String Extension Examples
Using EnsureFirstCharacterToUpper()
string result = "hello world".EnsureFirstCharacterToUpper();
// Result: "Hello world"
Using IsDigit(), IsNumeric(), and Validation Extensions
bool isDigit = "12345".IsDigit(); // true
bool isNumeric = "123.45".IsNumeric(); // true
bool isEmail = "user@example.com".IsEmailAddress(); // true
bool isGuid = "550e8400-e29b-41d4-a716-446655440000".IsGuid(); // true
Using Truncate()
string longText = "This is a very long text that needs truncation";
string short = longText.Truncate(20);
// Result: "This is a very lo..."
Using ToTitleCase() and ToPascalCase()
string title = "hello world".ToTitleCase(); // "Hello World"
string pascal = "hello world".ToPascalCase(); // "HelloWorld"
string camel = "HelloWorld".ToCamelCase(); // "helloWorld"
Using TrimToNull()
string? a = " Main Street ".TrimToNull(); // "Main Street"
string? b = " ".TrimToNull(); // null - nothing left, so treat it as not set
string? c = ((string?)null).TrimToNull(); // null
Using SplitIntoWords() and ToCasingStyle()
// Splits at separators, case changes and acronym ends - any input style works.
var words = "XMLParser.v2".SplitIntoWords(); // ["XML", "Parser", "v2"]
"getPetById".ToCasingStyle(CasingStyle.PascalCase); // "GetPetById"
"XMLParser".ToCasingStyle(CasingStyle.CamelCase); // "xmlParser"
"MyPetStore".ToCasingStyle(CasingStyle.KebabCase); // "my-pet-store"
"my-pet-store".ToCasingStyle(CasingStyle.SnakeCase); // "my_pet_store"
"myPetStore".ToCasingStyle(CasingStyle.UpperSnakeCase); // "MY_PET_STORE"
Code generation helpers
Using CSharpKeywordHelper and UniqueNameHelper
CSharpKeywordHelper.IsReservedKeyword("event"); // true
CSharpKeywordHelper.EscapeIfReservedKeyword("event"); // "@event"
CSharpKeywordHelper.IsValidIdentifier("2fa"); // false
CSharpKeywordHelper.EnsureIdentifierStart("2fa", "Header"); // "Header2fa"
var taken = new HashSet<string>(StringComparer.Ordinal);
UniqueNameHelper.Claim(taken, "id"); // "id"
UniqueNameHelper.Claim(taken, "id"); // "id2"
Using InvariantCasingHelper
// Invariant casing that keeps a letter as written when its cased form is no letter to this
// runtime (ICU can be newer than .NET's Unicode tables) - the same output on every platform.
string upper = InvariantCasingHelper.ToUpper("petStore"); // "PETSTORE"
string pascal = InvariantCasingHelper.ToUpperFirst("pet"); // "Pet"
Using HttpStatusCode.ToEnumName()
HttpStatusCode.NotFound.ToEnumName(); // "NotFound"
((HttpStatusCode)302).ToEnumName(); // "Found" (never the "Redirect" alias)
((HttpStatusCode)499).ToEnumName(); // "Status499"
File and process helpers
Using FileSystemTransaction to undo a half-done operation
// Files written through the transaction are put back (and new files and folders removed)
// unless the operation returns 0.
var exitCode = FileSystemTransaction.Run(() =>
{
FileSystemTransaction.CreateDirectory(projectFolder);
FileSystemTransaction.WriteAllText(Path.Combine(projectFolder, "Program.cs"), content);
return RunNextStep();
});
Using FileHelper.WriteAllTextIfChanged()
// Leaves the file (and its timestamp) alone when it already holds the content.
bool written = FileHelper.WriteAllTextIfChanged(new FileInfo("Generated.cs"), content, useLineFeedLineEndings: true);
Using GlobHelper
GlobHelper.IsMatch("/api/v1/users/42", "/api/**/users/*"); // true
GlobHelper.IsMatch("src/a/b/Program.cs", "src/**/*.cs"); // true
GlobHelper.IsMatchAny("/pets/1", new[] { "/pets/*", "/users" }); // true
Running a tool with ProcessHelper
// Find "git" on PATH, close its stdin so it cannot wait for input, stop it after 30 seconds,
// and read stdout and stderr apart.
var git = ProcessHelper.FindExecutableInPath("git");
var result = await ProcessHelper.ExecuteAsync(
new ProcessStartInfo(git!.FullName, "status --porcelain") { WorkingDirectory = repositoryPath },
TimeSpan.FromSeconds(30));
if (result.IsSuccessful)
{
Parse(result.StandardOutput); // warnings are in result.StandardError
}
NugetFeedClient examples
Using GetLatestStableVersionAsync(..) to find the latest stable version of a package
The client reads the flat container resource of nuget.org (or another NuGet v3 feed) and returns the highest
version that is not a prerelease. A version found is cached per instance; any failure (no network, an unknown
package, an unexpected answer, a cancellation) gives null instead of an exception.
INugetFeedClient client = new NugetFeedClient();
Version? latest = await client.GetLatestStableVersionAsync("Atc", cancellationToken);
Pass your own HttpClient (for example from IHttpClientFactory, or one over a fake HttpMessageHandler in tests),
and optionally the flat container address of another feed:
var client = new NugetFeedClient(
httpClient,
new Uri("https://pkgs.example.com/nuget/v3/flatcontainer/"));
SearchQueryHelper examples
Using Parse() to split a free-text search into terms
Words split on white space and commas, text in double quotes is one phrase (an unclosed quote runs to the end), and a full GUID becomes an identifier term. The helper only parses; the caller decides how each term matches, e.g. a word as a substring, a phrase as whole words and an identifier as an exact id.
var terms = SearchQueryHelper.Parse("\"Main Street 8\" Springfield 5b1eba26-8b25-f111-8341-7c1e52fbbe51");
// [ (Phrase, "Main Street 8"), (Word, "Springfield"), (Identifier, "5b1eba26-8b25-f111-8341-7c1e52fbbe51") ]
// Custom separators, or no GUID detection
var options = new SearchQueryOptions { WordSeparators = [';'], DetectGuids = false };
var custom = SearchQueryHelper.Parse("alpha;beta", options);
// [ (Word, "alpha"), (Word, "beta") ]
Enum Extension Examples
Using GetName() and GetDescription()
public enum Status
{
[Description("Currently Active")]
Active,
[Description("Temporarily Inactive")]
Inactive
}
Status status = Status.Active;
string name = status.GetName(); // "Active"
string description = status.GetDescription(); // "Currently Active"
Using GetEnumValue<T>()
Status status = EnumExtensions.GetEnumValue<Status>("Active");
// Result: Status.Active
// With description
Status statusFromDescription = EnumExtensions.GetEnumValueFromDescription<Status>("Currently Active");
// Result: Status.Active
Using ToEnumOrDefault<T>()
DayOfWeek a = "monday".ToEnumOrDefault(DayOfWeek.Sunday); // DayOfWeek.Monday
DayOfWeek b = "Funday".ToEnumOrDefault(DayOfWeek.Sunday); // DayOfWeek.Sunday (unknown name)
DayOfWeek c = "42".ToEnumOrDefault(DayOfWeek.Sunday); // DayOfWeek.Sunday (undefined number)
Claims Extension Examples
Using GetDisplayName(), GetUsername(), GetEmail() and GetAppId()
string? objectId = User.GetIdentity(); // Microsoft Entra ID object id (oid)
string? name = User.GetDisplayName(); // "name" claim, e.g. "Jane Doe"
string? username = User.GetUsername(); // ClaimTypes.Name, else "preferred_username"
string? email = User.GetEmail(); // ClaimTypes.Email, else "email", else an email-shaped username
string? appId = User.GetAppId(); // "azp" (v2 tokens), else "appid" (v1 tokens)
GuidHelper examples
Using CreateDeterministic()
// The same components always give the same Guid - a stable id derived from natural keys.
Guid id = GuidHelper.CreateDeterministic("device", "123");
// Always 9174bb27-8d27-375a-3046-9518b6264ddc
Collection Extension Examples
Using AddIfNotContains()
var list = new List<string> { "apple", "banana" };
list.AddIfNotContains("orange"); // Adds "orange"
list.AddIfNotContains("apple"); // Does nothing, already exists
Using ForEach()
var numbers = new List<int> { 1, 2, 3, 4, 5 };
numbers.ForEach(n => Console.WriteLine(n * 2));
Using IsNullOrEmpty()
List<string>? list = null;
bool isEmpty = list.IsNullOrEmpty(); // true
list = new List<string>();
isEmpty = list.IsNullOrEmpty(); // true
list.Add("item");
isEmpty = list.IsNullOrEmpty(); // false
DateTime Extension Examples
Using GetAge()
DateTime birthDate = new DateTime(1990, 5, 15);
int age = birthDate.GetAge(); // Current age in years
Using GetPrettyTimeDiff()
DateTime past = DateTime.Now.AddMinutes(-45);
string diff = past.GetPrettyTimeDiff();
// Result: "45 minutes ago"
Using IsBetween()
DateTime now = DateTime.Now;
DateTime start = DateTime.Now.AddHours(-1);
DateTime end = DateTime.Now.AddHours(1);
bool isBetween = now.IsBetween(start, end); // true
JSON Serialization Examples
Using JsonSerializerOptionsFactory
using Atc.Serialization;
// Create default options
var options = JsonSerializerOptionsFactory.Create();
// Serialize with camelCase
var json = JsonSerializer.Serialize(myObject, options);
// Deserialize
var obj = JsonSerializer.Deserialize<MyType>(json, options);
Using CopyTo() to apply options you cannot replace
// ASP.NET Core minimal APIs: copy every setting and converter, not just a few.
services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(
o => JsonSerializerOptionsFactory.Create().CopyTo(o.SerializerOptions));
Using StringEnumMemberJsonConverterFactory for strict and lenient enums
// Names come from [JsonStringEnumMemberName], else [EnumMember], else the member name.
// Non-nullable enums are strict; a nullable enum reads an unknown value (e.g. one a
// third-party API added later) as null instead of failing the whole response.
var options = new JsonSerializerOptions();
options.Converters.Add(new StringEnumMemberJsonConverterFactory(
onUnknownValue: (type, value) => logger.LogWarning("Unknown {Type} value {Value}", type.Name, value)));
Using AsyncEnumerableFactory.FromException<T>()
// A stream that fails when enumerated, e.g. to test error handling.
IAsyncEnumerable<Item> failing = AsyncEnumerableFactory.FromException<Item>(new HttpRequestException("Gone"));
Math and Geometry Examples
Using GeoSpatial Helpers
using Atc.Math.GeoSpatial;
var coordinate1 = new CartesianCoordinate(55.6761, 12.5683); // Copenhagen
var coordinate2 = new CartesianCoordinate(51.5074, -0.1278); // London
// Calculate distance in kilometers
double distance = coordinate1.DistanceTo(coordinate2);
Contributing
Contributions are welcome! Please see the main repository README for contribution guidelines.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.14)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.14)
- System.ComponentModel.Annotations (>= 5.0.0)
- System.Text.Json (>= 10.0.14)
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.14)
- System.ComponentModel.Annotations (>= 5.0.0)
NuGet packages (35)
Showing the top 5 NuGet packages that depend on Atc:
| Package | Downloads |
|---|---|
|
Atc.Rest
Atc.Rest is a basic collection of classes and extension methods for ASP.NET Core WebApi. |
|
|
Atc.CodeDocumentation
Atc.CodeDocumentation is a markdown generator for source code. |
|
|
Atc.OpenApi
Atc.OpenApi is a collection of classes and extension methods for Microsoft.OpenApi. |
|
|
Atc.XUnit
Atc.XUnit is a collection of helper method for code compliance of documentation and tests. |
|
|
Atc.Rest.ApiGenerator
Atc.Rest.ApiGenerator is a WebApi C# code generator using a OpenApi 3.0.x specification YAML file. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.1.0 | 460 | 11/9/2026 |
| 4.0.0 | 3,371 | 10/19/2026 |
| 3.0.186 | 6,951 | 8/25/2026 |
| 3.0.185 | 275 | 8/25/2026 |
| 3.0.181 | 5,426 | 7/29/2026 |
| 3.0.174 | 6,820 | 6/24/2026 |
| 3.0.173 | 403 | 6/24/2026 |
| 3.0.172 | 316 | 6/24/2026 |
| 3.0.67 | 6,120 | 4/25/2026 |
| 3.0.46 | 1,686 | 4/15/2026 |
| 3.0.45 | 594 | 4/10/2026 |
| 3.0.44 | 2,137 | 4/9/2026 |
| 3.0.43 | 278 | 4/9/2026 |
| 3.0.41 | 344 | 4/9/2026 |
| 3.0.40 | 320 | 4/9/2026 |
| 3.0.18 | 6,525 | 2/9/2026 |
| 3.0.16 | 8,914 | 12/15/2025 |
| 3.0.12 | 568 | 11/28/2025 |
| 3.0.9 | 801 | 11/21/2025 |
| 3.0.8 | 5,710 | 11/14/2025 |