/mcs/class/referencesource/System.Web.Extensions/ui/WebControls/QueryableDataSourceHelper.cs
C# | 242 lines | 195 code | 30 blank | 17 comment | 52 complexity | 60f0e068e7a81ee31194f1c6b17490a6 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
- namespace System.Web.UI.WebControls {
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.Diagnostics;
- using System.Globalization;
- using System.Linq;
- using System.Reflection;
- using System.Text;
- using System.Text.RegularExpressions;
- using System.Web;
- using System.Web.Resources;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- internal static class QueryableDataSourceHelper {
- // This regular expression verifies that parameter names are set to valid identifiers. This validation
- // needs to match the parser's identifier validation as done in the default block of NextToken().
- private static readonly string IdentifierPattern =
- @"^\s*[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}_]" + // first character
- @"[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}\p{Nd}\p{Pc}\p{Mn}\p{Mc}\p{Cf}_]*"; // remaining characters
- private static readonly Regex IdentifierRegex = new Regex(IdentifierPattern + @"\s*$");
- private static readonly Regex AutoGenerateOrderByRegex = new Regex(IdentifierPattern +
- @"(\s+(asc|ascending|desc|descending))?\s*$", RegexOptions.IgnoreCase); // order operators
- internal static IQueryable AsQueryable(object o) {
- IQueryable oQueryable = o as IQueryable;
- if (oQueryable != null) {
- return oQueryable;
- }
- // Wrap strings in IEnumerable<string> instead of treating as IEnumerable<char>.
- string oString = o as string;
- if (oString != null) {
- return Queryable.AsQueryable(new string[] { oString });
- }
- IEnumerable oEnumerable = o as IEnumerable;
- if (oEnumerable != null) {
- // IEnumerable<T> can be directly converted to an IQueryable<T>.
- Type genericType = FindGenericEnumerableType(o.GetType());
- if (genericType != null) {
- // The non-generic Queryable.AsQueryable gets called for array types, executing
- // the FindGenericType logic again. Might want to investigate way to avoid this.
- return Queryable.AsQueryable(oEnumerable);
- }
- // Wrap non-generic IEnumerables in IEnumerable<object>.
- List<object> genericList = new List<object>();
- foreach (object item in oEnumerable) {
- genericList.Add(item);
- }
- return Queryable.AsQueryable(genericList);
- }
- // Wrap non-IEnumerable types in IEnumerable<T>.
- Type listType = typeof(List<>).MakeGenericType(o.GetType());
- IList list = (IList)DataSourceHelper.CreateObjectInstance(listType);
- list.Add(o);
- return Queryable.AsQueryable(list);
- }
- public static IList ToList(this IQueryable query, Type dataObjectType) {
- MethodInfo toListMethod = typeof(Enumerable).GetMethod("ToList").MakeGenericMethod(dataObjectType);
- return (IList)toListMethod.Invoke(null, new object[] { query });
- }
- public static bool EnumerableContentEquals(IEnumerable enumerableA, IEnumerable enumerableB) {
- IEnumerator enumeratorA = enumerableA.GetEnumerator();
- IEnumerator enumeratorB = enumerableB.GetEnumerator();
- while (enumeratorA.MoveNext()) {
- if (!enumeratorB.MoveNext())
- return false;
- object itemA = enumeratorA.Current;
- object itemB = enumeratorB.Current;
- if (itemA == null) {
- if (itemB != null)
- return false;
- }
- else if (!itemA.Equals(itemB))
- return false;
- }
- if (enumeratorB.MoveNext())
- return false;
- return true;
- }
- public static Type FindGenericEnumerableType(Type type) {
- // Logic taken from Queryable.AsQueryable which accounts for Array types which are not
- // generic but implement the generic IEnumerable interface.
- while ((type != null) && (type != typeof(object)) && (type != typeof(string))) {
- if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IEnumerable<>))) {
- return type;
- }
- foreach (Type interfaceType in type.GetInterfaces()) {
- Type genericInterface = FindGenericEnumerableType(interfaceType);
- if (genericInterface != null) {
- return genericInterface;
- }
- }
- type = type.BaseType;
- }
- return null;
- }
- internal static IDictionary<string, object> ToEscapedParameterKeys(this ParameterCollection parameters, HttpContext context, Control control) {
- if (parameters != null) {
- return parameters.GetValues(context, control).ToEscapedParameterKeys(control);
- }
- return null;
- }
- internal static IDictionary<string, object> ToEscapedParameterKeys(this IDictionary parameters, Control owner) {
- Dictionary<string, object> escapedParameters = new Dictionary<string, object>(parameters.Count,
- StringComparer.OrdinalIgnoreCase);
- foreach (DictionaryEntry de in parameters) {
- string key = (string)de.Key;
- if (String.IsNullOrEmpty(key)) {
- throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
- AtlasWeb.LinqDataSourceView_ParametersMustBeNamed, owner.ID));
- }
- ValidateParameterName(key, owner);
- escapedParameters.Add('@' + key, de.Value);
- }
- return escapedParameters;
- }
- internal static IDictionary<string, object> ToEscapedParameterKeys(this IDictionary<string, object> parameters, Control owner) {
- Dictionary<string, object> escapedParameters = new Dictionary<string, object>(parameters.Count,
- StringComparer.OrdinalIgnoreCase);
- foreach (KeyValuePair<string, object> parameter in parameters) {
- string key = parameter.Key;
- if (String.IsNullOrEmpty(key)) {
- throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
- AtlasWeb.LinqDataSourceView_ParametersMustBeNamed, owner.ID));
- }
- ValidateParameterName(key, owner);
- escapedParameters.Add('@' + key, parameter.Value);
- }
- return escapedParameters;
- }
- internal static IQueryable CreateOrderByExpression(IOrderedDictionary parameters, IQueryable source, IDynamicQueryable queryable) {
- if (parameters != null && parameters.Count > 0) {
- //extract parameter values
- //extract the order by expression and apply it to the queryable
- string orderByExpression = GetOrderByClause(parameters.ToDictionary());
- if (!String.IsNullOrEmpty(orderByExpression)) {
- return queryable.OrderBy(source, orderByExpression);
- }
- }
- return source;
- }
- internal static IQueryable CreateWhereExpression(IDictionary<string, object> parameters, IQueryable source, IDynamicQueryable queryable) {
- if (parameters != null && parameters.Count > 0) {
- //extract the where clause
- WhereClause clause = GetWhereClause(parameters);
- if (!String.IsNullOrEmpty(clause.Expression)) {
- //transform the current query with the where clause
- return queryable.Where(source, clause.Expression, clause.Parameters);
- }
- }
- return source;
- }
- private static WhereClause GetWhereClause(IDictionary<string, object> whereParameters) {
- Debug.Assert((whereParameters != null) && (whereParameters.Count > 0));
- WhereClause whereClause = new WhereClause();
- whereClause.Parameters = new Dictionary<string, object>(whereParameters.Count);
- StringBuilder where = new StringBuilder();
- int index = 0;
- foreach (KeyValuePair<string, object> parameter in whereParameters) {
- string key = parameter.Key;
- string value = (parameter.Value == null) ? null : parameter.Value.ToString();
- // exclude null and empty values.
- if (!(String.IsNullOrEmpty(key) || String.IsNullOrEmpty(value))) {
- string newKey = "@p" + index++;
- if (where.Length > 0) {
- where.Append(" AND ");
- }
- where.Append(key);
- where.Append(" == ");
- where.Append(newKey);
- whereClause.Parameters.Add(newKey, parameter.Value);
- }
- }
- whereClause.Expression = where.ToString();
- return whereClause;
- }
- private static string GetOrderByClause(IDictionary<string, object> orderByParameters) {
- Debug.Assert((orderByParameters != null) && (orderByParameters.Count > 0));
- StringBuilder orderBy = new StringBuilder();
- foreach (KeyValuePair<string, object> parameter in orderByParameters) {
- string value = (string)parameter.Value;
- // exclude null and empty values.
- if (!String.IsNullOrEmpty(value)) {
- string name = parameter.Key;
- //validate parameter name
- ValidateOrderByParameter(name, value);
- if (orderBy.Length > 0) {
- orderBy.Append(", ");
- }
- orderBy.Append(value);
- }
- }
- return orderBy.ToString();
- }
- internal static void ValidateOrderByParameter(string name, string value) {
- if (!AutoGenerateOrderByRegex.IsMatch(value)) {
- throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
- AtlasWeb.LinqDataSourceView_InvalidOrderByFieldName, value, name));
- }
- }
- internal static void ValidateParameterName(string name, Control owner) {
- if (!IdentifierRegex.IsMatch(name)) {
- throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
- AtlasWeb.LinqDataSourceView_InvalidParameterName, name, owner.ID));
- }
- }
- private class WhereClause {
- public string Expression { get; set; }
- public IDictionary<string, object> Parameters { get; set; }
- }
- }
- }