Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
C# method to validate a string-based OrderBy clause to be used in a dynamic LINQ statement
internal void ValidateOrderByClause(string orderBy, string[] supportedOrderByFields)
{
if (!string.IsNullOrWhiteSpace(orderBy))
{
var orderBys = orderBy.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (var orderByClause in orderBys)
{
var orderByClauseParts = orderByClause.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
var orderByClauseField = orderByClauseParts[0];
if (!supportedOrderByFields.Contains(orderByClauseField, StringComparer.OrdinalIgnoreCase))
{
throw new Exception($"'{orderByClauseField}' is not a supported ORDER BY field. Supported fields: {string.Join(",", supportedOrderByFields)}");
}
if (orderByClauseParts.Length > 1)
{
var orderByClauseSortOrder = orderByClauseParts[1];
var supportedOrderBySortOrders = new[] { "ASC", "ASCENDING", "DESC", "DESCENDING" };
if (!supportedOrderBySortOrders.Contains(orderByClauseSortOrder, StringComparer.OrdinalIgnoreCase))
{
throw new Exception($"'{orderByClauseSortOrder}' is not a supported ORDER BY sort order. Supported sort orders: {string.Join(",", supportedOrderBySortOrders)}");
}
}
}
}
}
@randyburden

This comment has been minimized.

Copy link
Owner Author

@randyburden randyburden commented Aug 13, 2019

Below is an alternative implementation inspired by the previous version.

using System;

namespace Utilities
{
    /// <summary>
    /// Validates Order By clauses.
    /// </summary>
    public static class OrderByClauseValidator
    {
        /// <summary>Represents a validated Order By clause.</summary>
        public class ValidateOrderByClauseResult
        {
            /// <summary>Field that will be sorted on.</summary>
            public string SortField { get; set; }

            /// <summary>Order the field will be sorted on.</summary>
            public string SortOrder { get; set; }

            /// <summary>Valid Order By clause.</summary>
            public string OrderByClause => $"{SortField} {SortOrder}";
        }

        /// <summary>Validates the parts of an Order By clause, primarily to prevent SQL injection.</summary>
        /// <param name="sortField">Field that will be sorted on.</param>
        /// <param name="sortOrder">Order the field will be sorted. i.e. ASC, DESC</param>
        /// <param name="supportedOrderByFields">List of valid field names that can be sorted on.</param>
        /// <returns>A validated order by clause.</returns>
        public static ValidateOrderByClauseResult ValidateOrderByClause(string sortField, string sortOrder, string[] supportedOrderByFields)
        {
            // Begin: Validate and map sort field to prevent SQL injection
            if (string.IsNullOrWhiteSpace(sortField))
            {
                throw new ArgumentNullException(nameof(sortField));
            }

            var result = new ValidateOrderByClauseResult();

            foreach (var supportedOrderByField in supportedOrderByFields)
            {
                if (sortField.Equals(supportedOrderByField, StringComparison.CurrentCultureIgnoreCase))
                {
                    result.SortField = supportedOrderByField;
                }
            }

            if (result.SortField is null)
            {
                throw new ArgumentException($"'{sortField}' is not a supported ORDER BY sort field. Supported sort fields: {string.Join(", ", supportedOrderByFields)}");
            }
            // End: Validate and map sort field to prevent SQL injection

            // Begin: Validate and map sort order to prevent SQL injection
            if (string.IsNullOrWhiteSpace(sortOrder))
            {
                throw new ArgumentNullException(nameof(sortOrder));
            }

            var supportedOrderBySortOrders = new[] { "ASC", "DESC" };

            foreach (var supportedOrderBySortOrder in supportedOrderBySortOrders)
            {
                if (sortOrder.Equals(supportedOrderBySortOrder, StringComparison.CurrentCultureIgnoreCase))
                {
                    result.SortOrder = supportedOrderBySortOrder;
                }
            }

            if (result.SortOrder is null)
            {
                throw new ArgumentException($"'{sortOrder}' is not a supported ORDER BY sort order. Supported sort fields: {string.Join(", ", supportedOrderBySortOrders)}");
            }
            // End: Validate and map sort order to prevent SQL injection

            return result;
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.