C# Extension Methods that come in handy for an ASP.Net Project

C# Extension Methods that come in handy for an ASP.Net Project

In the realm of C# and ASP.NET development, extension methods serve as invaluable tools, empowering developers to enhance the expressiveness and efficiency of their code. In this blog post, we will delve into some of the basic extension methods that any ASP.Net Core project needs and can elevate your web development projects.

HTTPContext Extensions

Get Base Path

public static string GetBasePath(this HttpContext httpContext)
{
    return $"{httpContext.Request.Scheme}://{httpContext.Request.Host}";
}

Check if the Request Header has a particular key

public static bool HasRequestHeader(this HttpContext httpContext, string headerName)
{
    return httpContext.Request.Headers.ContainsKey(headerName);
}

Check if the Response Header has a particular key

public static bool HasResponseHeader(this HttpContext httpContext, string headerName)
{
    return httpContext.Response.Headers.ContainsKey(headerName);
}

Check if the Request Header key has the required value

public static bool HasRequestHeaderValue(this HttpContext httpContext, string headerName, string headerValue)
{
    return httpContext.Request.Headers.TryGetValue(headerName, out var header)
        && header.Any(a => a.Equals(headerValue, StringComparison.OrdinalIgnoreCase));
}

Check if the Response Header key has the required value

public static bool HasResponseHeaderValue(this HttpContext httpContext, string headerName, string headerValue)
{
    return httpContext.Response.Headers.TryGetValue(headerName, out var header)
        && header.Any(a => a.Equals(headerValue, StringComparison.OrdinalIgnoreCase));
}

IEnumerable Extensions

Convert any IEnumerable to CSV String

public static string ConvertToCSVString<T>(this IEnumerable<T> items)
{
    if (items.Any())
    {
        var lines = new List<string>();
        var header = string.Empty;

        if (items.FirstOrDefault().GetType() == typeof(JObject))
        {
            var jObject = (JObject)Convert.ChangeType(items.FirstOrDefault(), typeof(JObject));

            header = string.Join(",", jObject.Properties().Select(x => x.Name));

            lines.Add(header);

            ////DO NOT include the starting and ending quotes inside the $ string interpolation.
            var valueLines = items.Select(row =>
                                    string.Join(",", header.Split(',')
                                        .Select(a => "\"" + $"{((JObject)Convert.ChangeType(row, typeof(JObject))).GetValue(a)}"?
                                                        .Replace(Environment.NewLine, string.Empty, StringComparison.OrdinalIgnoreCase)
                                                        .Replace("\"", "\"\"", StringComparison.OrdinalIgnoreCase)
                                                        + "\""
                                                        )));

            lines.AddRange(valueLines);
        }
        else
        {
            var props = items.FirstOrDefault().GetType().GetProperties();

            header = string.Join(",", props.Select(x => x.Name));

            lines.Add(header);

            //DO NOT include the starting and ending quotes inside the $ string interpolation.
            var valueLines = items.Select(row =>
                                    string.Join(",", header.Split(',')
                                        .Select(a => "\"" + $"{row.GetType().GetProperty(a).GetValue(row, null)}"?
                                                        .Replace(Environment.NewLine, string.Empty, StringComparison.OrdinalIgnoreCase)
                                                        .Replace("\"", "\"\"", StringComparison.OrdinalIgnoreCase)
                                                        + "\""
                                                        )));

            lines.AddRange(valueLines);
        }

        var csvString = string.Join("\r\n", lines.ToArray());

        return csvString;
    }
    else
    {
        return string.Empty;
    }
}

Convert any IEnumerable to DataTable

public static DataTable ToDataTable<T>(this IEnumerable<T> items)
{
    DataTable dataTable = new DataTable(typeof(T).Name);

    PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
    foreach (PropertyInfo prop in Props)
    {
        dataTable.Columns.Add(prop.Name);
    }
    foreach (T item in items)
    {
        var values = new object[Props.Length];
        for (int i = 0; i < Props.Length; i++)
        {
            values[i] = Props[i].GetValue(item, null);
        }
        dataTable.Rows.Add(values);
    }

    return dataTable;
}

Session Extensions

Replace a value in a Session key

public static void Replace(this ISession session, string key, object data)
{
    if (session.Keys.Any(x => x.Equals(key, StringComparison.OrdinalIgnoreCase)))
    {
        session.Remove(key);
    }

    session.SetString(key, JsonConvert.SerializeObject(data));
}

Get value from a Session key

public static bool TryGet<T>(this ISession session, string key, out T data, bool removeKey = false)
{
    if (session.Keys.Any(x => x.Equals(key, StringComparison.OrdinalIgnoreCase)))
    {
        var objString = session.GetString(key);

        data = JsonConvert.DeserializeObject<T>(objString);

        if (removeKey)
        {
            session.Remove(key);
        }

        return true;
    }

    data = default;
    return false;
}

ClaimsPrincipal Extensions

Check if the claims has a particular Role

public static bool HasRole(this ClaimsPrincipal principal, string role)
{
    return principal.HasClaim(c =>
                                    c.Type == ClaimTypes.Role &&
                                    c.Value.Equals(role, StringComparison.OrdinalIgnoreCase));
}

Get Roles from the claims

public static IEnumerable<string> GetRoles(this ClaimsPrincipal principal)
{
    return principal.Claims.Where(c => c.Type == ClaimTypes.Role).Select(s => s.Value);
}

Get a particular claim from the claims

 public static T GetClaim<T>(this ClaimsPrincipal principal, string claim)
 {
     var result = principal?.Claims?.FirstOrDefault(f => f.Type.Equals(claim, StringComparison.OrdinalIgnoreCase))?.Value;

     return (T)Convert.ChangeType(result, typeof(T));
 }

DateTime Extensions

Convert to a different TimeZone

public static DateTime ConvertToTimeZone(this DateTime dateTime, string timeZoneId)
{
    return TimeZoneInfo.ConvertTimeFromUtc(dateTime, TimeZoneInfo.FindSystemTimeZoneById(timeZoneId));
}

Check if a given DateTime is between a time range

public static bool IsBetweenTimeRange(this DateTime comparisonTime, DateTime? startDate, DateTime? endDate)
{
    return (startDate.HasValue ? comparisonTime >= startDate.Value : true) && (endDate.HasValue ? comparisonTime <= endDate.Value : true);
}

Check if a give DateTimeOffset is between a time range

public static bool IsBetweenTimeRange(this DateTime comparisonTime, DateTimeOffset? startDate, DateTimeOffset? endDate)
{
    return comparisonTime.IsBetweenTimeRange(startDate.HasValue ? startDate.Value.DateTime : null, endDate.HasValue ? endDate.Value.DateTime : null);
}

Convert to a DateTimeOffset based on a TimeZone

public static DateTimeOffset? ToDateTimeOffset(this DateTime? dateTime, string timeZoneId)
{
    return dateTime.HasValue ? new DateTimeOffset(dateTime.Value, TimeZoneInfo.FindSystemTimeZoneById(timeZoneId).BaseUtcOffset) : null;
}

Enum Extensions

Get display name of an Enum

public static string GetDisplayName(this Enum enumValue)
{
    var displayName = enumValue.GetType().GetMember(enumValue.ToString()).FirstOrDefault().GetCustomAttribute<DisplayAttribute>()?.GetName();

    return string.IsNullOrWhiteSpace(displayName) ? enumValue.ToString() : displayName;
}

HTTPResponseMessage Extensions

Ensure the HTTPResponseMessage has a Success Status code and log failures

public static async Task EnsureSuccessStatusCodeAndLogFailures(this HttpResponseMessage httpResponseMessage, ILogger logger)
{
    if (httpResponseMessage == null)
    {
        throw new ArgumentNullException(nameof(httpResponseMessage));
    }
    if (logger == null)
    {
        throw new ArgumentNullException(nameof(logger));
    }

    if (!httpResponseMessage.IsSuccessStatusCode)
    {
        var response = await httpResponseMessage.Content?.ReadAsStringAsync();

        var requestUri = httpResponseMessage.RequestMessage?.RequestUri;

        logger.LogError($"HTTP call to {requestUri} returned status code {httpResponseMessage.StatusCode} with response {response}");
    }

    httpResponseMessage.EnsureSuccessStatusCode();
}

TokenResponse Extensions

Ensure the TokenResponse has a Success Status and log failures

public static void CheckResponseAndLogFailures(this TokenResponse tokenResponse, ILogger logger)
{
    if (tokenResponse == null)
    {
        throw new ArgumentNullException(nameof(tokenResponse));
    }
    if (logger == null)
    {
        throw new ArgumentNullException(nameof(logger));
    }

    if (tokenResponse.IsError)
    {
        var response = JsonConvert.SerializeObject(tokenResponse);

        logger.LogError("Access Token call to returned with error and data: {data}", response);
    }
}

String Extensions

Slugify

public static string Slugify(this string phrase)
{
    if (string.IsNullOrWhiteSpace(phrase))
    {
        return string.Empty;
    }

    var output = phrase.RemoveAccents().ToLower();

    output = Regex.Replace(output, @"[^A-Za-z0-9\s-]", "");

    output = Regex.Replace(output, @"\s+", " ").Trim();

    output = Regex.Replace(output, @"\s", "-");

    return output;
}

public static string RemoveAccents(this string text)
{
    if (string.IsNullOrWhiteSpace(text))
        return text;

    text = text.Normalize(NormalizationForm.FormD);
    char[] chars = text
        .Where(c => CharUnicodeInfo.GetUnicodeCategory(c)
        != UnicodeCategory.NonSpacingMark).ToArray();

    return new string(chars).Normalize(NormalizationForm.FormC);
}

Check if a email is valid

public static bool IsValidEmail(this string email)
{
    var isValid = true;

    try
    {
        var emailAddress = new MailAddress(email.Trim());
    }
    catch
    {
        isValid = false;
    }

    return isValid;
}

Did you find this article valuable?

Support Venkatesan Rethinam by becoming a sponsor. Any amount is appreciated!