.NET
...see more

When working with JsonElement in C#, calling methods like TryGetProperty on a default or uninitialized JsonElement can cause runtime exceptions. This usually happens when the JsonElement has not been properly assigned a value.

To avoid this issue, always check whether the JsonElement is valid before accessing its properties. A safe way to do this is by checking its ValueKind.

Here’s a safer extension method that returns a string property only if it exists and the element is valid:

public static string? GetStringProperty(this JsonElement element, string propertyName)
{
    if (element.ValueKind == JsonValueKind.Undefined)
        return null;

    return element.TryGetProperty(propertyName, out var prop) && prop.ValueKind == JsonValueKind.String
        ? prop.GetString()
        : null;
}

This ensures that your code won’t throw an InvalidOperationException when the JsonElement is default.

Use this method when reading from JSON documents where property existence isn’t guaranteed.

...see more

What’s the Problem?

When writing unit tests for a custom DelegatingHandler, you might try calling:

var response = await handler.SendAsync(request, cancellationToken);

But this will cause a compiler error. Why? Because SendAsync in DelegatingHandler is protected, meaning you can't call it directly from your test project.

The Simple Solution

Use HttpMessageInvoker, which is designed to work with any HttpMessageHandler (including DelegatingHandler). It provides a public SendAsync method, so you can easily test your handler:

var handler = new YourCustomHandler
{
    InnerHandler = new DummyHandler() // Replace with mock/stub as needed
};

var invoker = new HttpMessageInvoker(handler);
var response = await invoker.SendAsync(request, cancellationToken);

This allows you to simulate HTTP requests through your custom handler, without using HttpClient.

Why This Works

  • DelegatingHandler is a subclass of HttpMessageHandler.
  • HttpMessageInvoker takes any HttpMessageHandler and exposes a public way to send HTTP requests.
  • This bypasses the visibility issue with protected SendAsync.

Tip for Better Testing

Use a mock InnerHandler to control the behavior of the response. This helps you test how your DelegatingHandler reacts to different scenarios.

...see more

When writing unit tests in .NET using Assert.Contains, it's easy to accidentally check for exact matches when you only want to check if a string is part of another.

Here’s a common mistake:

Assert.Contains("TestCookie=TestValue", cookieStrings);

This fails if cookieStrings contains items like "TestCookie=TestValue; Path=/; HttpOnly" — because "TestCookie=TestValue" is not an exact match to any item.

How to Fix It

Use the lambda version of Assert.Contains to check for a substring match:

Assert.Contains(cookieStrings, c => c.Contains("TestCookie=TestValue"));

This makes sure that at least one string in the collection includes "TestCookie=TestValue" somewhere inside it.

Example Use Case

In a test where you're adding a cookie to an HttpClient, you might write:

Assert.Contains(
    httpClient.DefaultRequestHeaders.GetValues("Cookie"),
    c => c.Contains("TestCookie=TestValue")
);

Summary

  • Assert.Contains(item, collection) checks for exact matches.
  • Use Assert.Contains(collection, predicate) to check for substring matches.
  • Ideal for validating headers, cookies, or complex strings in collections.
...see more

Summary:
Masking replaces the middle part of a string with repeated mask characters (like *), preserving the string’s total length and showing only a visible prefix and suffix. If the string is too short, it masks the entire string. The mask character can be customized.

Key points:

  • Shows a defined number of characters at the start and end of the string.
  • Replaces the middle characters with a masking character (default *).
  • Supports custom mask characters.
  • If the string is too short to be partially masked, it masks the entire string.

Example Implementation:

public static string Mask(string input, int prefixLength = 4, int suffixLength = 4, char maskCharacter = '*')
{
    if (string.IsNullOrWhiteSpace(input)) return new string(maskCharacter, 3);
    if (prefixLength < 0 || suffixLength < 0)
        throw new ArgumentOutOfRangeException("Prefix and suffix lengths cannot be negative.");

    int inputLength = input.Length;

    if (prefixLength + suffixLength >= inputLength)
    {
        return new string(maskCharacter, inputLength);
    }

    string prefix = input.Substring(0, prefixLength);
    string suffix = input.Substring(inputLength - suffixLength);
    string maskedPart = new string(maskCharacter, inputLength - prefixLength - suffixLength);

    return prefix + maskedPart + suffix;
}

Use Case:
Ideal when you need to display partial information while maintaining the same length, such as masking credit card numbers or tokens in a UI.

...see more

Redaction hides sensitive parts of a string by keeping only a visible prefix and suffix and inserting a customizable placeholder (such as "...") in the middle. If the string is too short, it returns just the placeholder to avoid revealing data.

Key points:

  • Shows a prefix and suffix of the string, with a redaction string in between.
  • If the string is too short, it returns just the redaction string to avoid exposing sensitive data.
  • Supports customizable redaction strings (e.g., "...", "###", or emojis).

Example Implementation:

public static string Redact(string token, int prefixLength = 4, int suffixLength = 4, string redactionString = "...")
{
    if (string.IsNullOrWhiteSpace(token)) return "[Token is null or empty]";
    if (prefixLength < 0 || suffixLength < 0) return "[Invalid prefix or suffix length]";
    if (string.IsNullOrEmpty(redactionString)) redactionString = "...";

    int tokenLength = token.Length;
    int minLengthForFullRedaction = prefixLength + suffixLength + redactionString.Length;

    if (tokenLength >= minLengthForFullRedaction)
    {
        string prefix = token.Substring(0, prefixLength);
        string suffix = token.Substring(tokenLength - suffixLength);
        return $"{prefix}{redactionString}{suffix}";
    }

    int minLengthForPrefixOnly = prefixLength + redactionString.Length;

    if (tokenLength >= minLengthForPrefixOnly)
    {
        string prefix = token.Substring(0, prefixLength);
        return $"{prefix}{redactionString}";
    }

    return redactionString;
}

Use Case:
Useful for logs or UI where a brief summary of sensitive data is needed without showing the entire value.

...see more

When handling tokens in .NET applications, it's essential to avoid logging them in full due to the potential exposure of sensitive information. A best practice is to redact tokens before logging by showing only a prefix and/or suffix.

Here’s a robust approach:

  1. Redact tokens safely: Display only the first few and last few characters of the token, separated by ellipses (...). If the token is too short to show both, consider showing only the prefix followed by ..., or return a standardized warning.

  2. Implement a helper method: Encapsulate redaction logic in a shared utility to ensure consistent and secure usage throughout the codebase.

public static string RedactToken(string token, int prefixLength = 6, int suffixLength = 4)
{
    if (string.IsNullOrEmpty(token))
        return "[null or empty token]";

    int minLengthForFullRedaction = prefixLength + suffixLength;

    if (token.Length >= minLengthForFullRedaction)
    {
        var prefix = token.Substring(0, prefixLength);
        var suffix = token.Substring(token.Length - suffixLength);
        return $"{prefix}...{suffix}";
    }

    int minLengthForPrefixOnly = prefixLength + 3; // For "..."
    if (token.Length >= minLengthForPrefixOnly)
    {
        var prefix = token.Substring(0, prefixLength);
        return $"{prefix}...";
    }

    return "[token too short to redact securely]";
}
  1. Optional hashing for debugging: If correlation is needed without revealing the token, hash it using a secure algorithm (e.g., SHA256) and log only the hash.

By centralizing redaction in a reusable helper and applying consistent rules, applications can balance debugging needs with security best practices.

...see more

C#'s async/await pattern simplifies asynchronous programming, but integrating it into console applications poses a challenge. The traditional static void Main() method can't be marked as async, leading to compiler errors when attempting to use await directly.

Workaround Strategies:

  • Separate Async Method: Encapsulate asynchronous operations within a separate method marked as async. Then, invoke this method from Main() using .GetAwaiter().GetResult() to execute it synchronously. This approach ensures exceptions are unwrapped properly, avoiding the AggregateException that occurs with .Result or .Wait().

  • Async Main (C# 7.1 and Later): Starting with C# 7.1, you can define the entry point as static async Task Main(), allowing the use of await directly within Main(). This modernizes the approach and simplifies asynchronous code execution in console applications.

For a detailed explanation and code examples see Async/await in a console application.

...see more

When handling sensitive information like passwords, API keys, or personal data, it’s important to protect this data when displaying or logging it. Two common techniques for this are redaction and masking.

  • Redaction shortens the string by showing only the start and end, replacing the middle with a placeholder such as "...". This gives a clear but limited preview of the data.
  • Masking hides part of the string by replacing the middle characters with a repeated symbol (like *), keeping the original length intact and showing only limited characters at the start and end.

Choosing between redaction and masking depends on your needs: whether you want to reduce visible length for compact display (redaction), or maintain length for format consistency while hiding data (masking).

...see more

Logging is an essential part of application development for debugging, monitoring, and understanding the flow of execution, especially in complex systems. When logging in a C# method with parameters that need validation, it's crucial to follow best practices to ensure clear and useful log messages. Below is a sample demonstrating how to log and validate parameters in a C# method:

public bool ValidateAndProcessData(string data)
{
    // Log the start of the method
    _logger.LogInformation("ValidateAndProcessData method started");

    // Validate input data
    if (string.IsNullOrEmpty(data))
    {
        _logger.LogError("Input data is null or empty");
        throw new ArgumentException("Input data cannot be null or empty", nameof(data));
    }

    try
    {
        // Process data
        _logger.LogInformation("Processing data: {data}", data);

        // Simulating processing time
        System.Threading.Thread.Sleep(1000);

        _logger.LogInformation("Data processed successfully");
        return true;
    }
    catch (Exception ex)
    {
        // Log any exceptions that occur during processing
        _logger.LogError(ex, "Error processing data: {data}", data);
        throw; // Re-throw the exception for higher-level handling
    }
    finally
    {
        // Log the end of the method
        _logger.LogInformation("ValidateAndProcessData method completed");
    }
}

By following this sample, you ensure that your method logs relevant information about parameter validation and method execution, making it easier to debug and monitor your application's behavior.

...see more

In a console apps, there is often a need to obtain user input from the console while ensuring that the input is not empty or only whitespace characters.

In this sample, we define a method GetUserInput that takes an optional message parameter. It continuously prompts the user until a non-empty, non-whitespace input is provided.

static string GetUserInput(string message = "Please enter some input:")
{
    string input;
    do
    {
        Console.WriteLine(message);
        input = Console.ReadLine()?.Trim();
    } while (string.IsNullOrWhiteSpace(input));
    return input;
}

Explanation:

  • message parameter allows customizing input prompt message.
  • Console.ReadLine()?.Trim() reads user input and trims leading/trailing whitespace.
  • The ?. operator is used for null-conditional access, ensuring that Console.ReadLine() doesn't throw a null reference exception if the input is null.
  • do-while loop ensures user input is not empty or whitespace.
Add to Set
  • .NET
  • Agile
  • AI
  • ASP.NET Core
  • Azure
  • C#
  • Cloud Computing
  • CSS
  • EF Core
  • HTML
  • JavaScript
  • Microsoft Entra
  • PowerShell
  • Quotes
  • React
  • Security
  • Software Development
  • SQL References
  • Technologies
  • Testing
  • Visual Studio
  • Windows
 
Sets