PageRenderTime 23ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/referencesource/System.Web.Extensions/ui/WebControls/QueryableDataSourceHelper.cs

https://github.com/pruiz/mono
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
  1. namespace System.Web.UI.WebControls {
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Collections.Specialized;
  6. using System.Diagnostics;
  7. using System.Globalization;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.Text;
  11. using System.Text.RegularExpressions;
  12. using System.Web;
  13. using System.Web.Resources;
  14. using System.Web.UI;
  15. using System.Web.UI.WebControls;
  16. internal static class QueryableDataSourceHelper {
  17. // This regular expression verifies that parameter names are set to valid identifiers. This validation
  18. // needs to match the parser's identifier validation as done in the default block of NextToken().
  19. private static readonly string IdentifierPattern =
  20. @"^\s*[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}_]" + // first character
  21. @"[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}\p{Nd}\p{Pc}\p{Mn}\p{Mc}\p{Cf}_]*"; // remaining characters
  22. private static readonly Regex IdentifierRegex = new Regex(IdentifierPattern + @"\s*$");
  23. private static readonly Regex AutoGenerateOrderByRegex = new Regex(IdentifierPattern +
  24. @"(\s+(asc|ascending|desc|descending))?\s*$", RegexOptions.IgnoreCase); // order operators
  25. internal static IQueryable AsQueryable(object o) {
  26. IQueryable oQueryable = o as IQueryable;
  27. if (oQueryable != null) {
  28. return oQueryable;
  29. }
  30. // Wrap strings in IEnumerable<string> instead of treating as IEnumerable<char>.
  31. string oString = o as string;
  32. if (oString != null) {
  33. return Queryable.AsQueryable(new string[] { oString });
  34. }
  35. IEnumerable oEnumerable = o as IEnumerable;
  36. if (oEnumerable != null) {
  37. // IEnumerable<T> can be directly converted to an IQueryable<T>.
  38. Type genericType = FindGenericEnumerableType(o.GetType());
  39. if (genericType != null) {
  40. // The non-generic Queryable.AsQueryable gets called for array types, executing
  41. // the FindGenericType logic again. Might want to investigate way to avoid this.
  42. return Queryable.AsQueryable(oEnumerable);
  43. }
  44. // Wrap non-generic IEnumerables in IEnumerable<object>.
  45. List<object> genericList = new List<object>();
  46. foreach (object item in oEnumerable) {
  47. genericList.Add(item);
  48. }
  49. return Queryable.AsQueryable(genericList);
  50. }
  51. // Wrap non-IEnumerable types in IEnumerable<T>.
  52. Type listType = typeof(List<>).MakeGenericType(o.GetType());
  53. IList list = (IList)DataSourceHelper.CreateObjectInstance(listType);
  54. list.Add(o);
  55. return Queryable.AsQueryable(list);
  56. }
  57. public static IList ToList(this IQueryable query, Type dataObjectType) {
  58. MethodInfo toListMethod = typeof(Enumerable).GetMethod("ToList").MakeGenericMethod(dataObjectType);
  59. return (IList)toListMethod.Invoke(null, new object[] { query });
  60. }
  61. public static bool EnumerableContentEquals(IEnumerable enumerableA, IEnumerable enumerableB) {
  62. IEnumerator enumeratorA = enumerableA.GetEnumerator();
  63. IEnumerator enumeratorB = enumerableB.GetEnumerator();
  64. while (enumeratorA.MoveNext()) {
  65. if (!enumeratorB.MoveNext())
  66. return false;
  67. object itemA = enumeratorA.Current;
  68. object itemB = enumeratorB.Current;
  69. if (itemA == null) {
  70. if (itemB != null)
  71. return false;
  72. }
  73. else if (!itemA.Equals(itemB))
  74. return false;
  75. }
  76. if (enumeratorB.MoveNext())
  77. return false;
  78. return true;
  79. }
  80. public static Type FindGenericEnumerableType(Type type) {
  81. // Logic taken from Queryable.AsQueryable which accounts for Array types which are not
  82. // generic but implement the generic IEnumerable interface.
  83. while ((type != null) && (type != typeof(object)) && (type != typeof(string))) {
  84. if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IEnumerable<>))) {
  85. return type;
  86. }
  87. foreach (Type interfaceType in type.GetInterfaces()) {
  88. Type genericInterface = FindGenericEnumerableType(interfaceType);
  89. if (genericInterface != null) {
  90. return genericInterface;
  91. }
  92. }
  93. type = type.BaseType;
  94. }
  95. return null;
  96. }
  97. internal static IDictionary<string, object> ToEscapedParameterKeys(this ParameterCollection parameters, HttpContext context, Control control) {
  98. if (parameters != null) {
  99. return parameters.GetValues(context, control).ToEscapedParameterKeys(control);
  100. }
  101. return null;
  102. }
  103. internal static IDictionary<string, object> ToEscapedParameterKeys(this IDictionary parameters, Control owner) {
  104. Dictionary<string, object> escapedParameters = new Dictionary<string, object>(parameters.Count,
  105. StringComparer.OrdinalIgnoreCase);
  106. foreach (DictionaryEntry de in parameters) {
  107. string key = (string)de.Key;
  108. if (String.IsNullOrEmpty(key)) {
  109. throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
  110. AtlasWeb.LinqDataSourceView_ParametersMustBeNamed, owner.ID));
  111. }
  112. ValidateParameterName(key, owner);
  113. escapedParameters.Add('@' + key, de.Value);
  114. }
  115. return escapedParameters;
  116. }
  117. internal static IDictionary<string, object> ToEscapedParameterKeys(this IDictionary<string, object> parameters, Control owner) {
  118. Dictionary<string, object> escapedParameters = new Dictionary<string, object>(parameters.Count,
  119. StringComparer.OrdinalIgnoreCase);
  120. foreach (KeyValuePair<string, object> parameter in parameters) {
  121. string key = parameter.Key;
  122. if (String.IsNullOrEmpty(key)) {
  123. throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
  124. AtlasWeb.LinqDataSourceView_ParametersMustBeNamed, owner.ID));
  125. }
  126. ValidateParameterName(key, owner);
  127. escapedParameters.Add('@' + key, parameter.Value);
  128. }
  129. return escapedParameters;
  130. }
  131. internal static IQueryable CreateOrderByExpression(IOrderedDictionary parameters, IQueryable source, IDynamicQueryable queryable) {
  132. if (parameters != null && parameters.Count > 0) {
  133. //extract parameter values
  134. //extract the order by expression and apply it to the queryable
  135. string orderByExpression = GetOrderByClause(parameters.ToDictionary());
  136. if (!String.IsNullOrEmpty(orderByExpression)) {
  137. return queryable.OrderBy(source, orderByExpression);
  138. }
  139. }
  140. return source;
  141. }
  142. internal static IQueryable CreateWhereExpression(IDictionary<string, object> parameters, IQueryable source, IDynamicQueryable queryable) {
  143. if (parameters != null && parameters.Count > 0) {
  144. //extract the where clause
  145. WhereClause clause = GetWhereClause(parameters);
  146. if (!String.IsNullOrEmpty(clause.Expression)) {
  147. //transform the current query with the where clause
  148. return queryable.Where(source, clause.Expression, clause.Parameters);
  149. }
  150. }
  151. return source;
  152. }
  153. private static WhereClause GetWhereClause(IDictionary<string, object> whereParameters) {
  154. Debug.Assert((whereParameters != null) && (whereParameters.Count > 0));
  155. WhereClause whereClause = new WhereClause();
  156. whereClause.Parameters = new Dictionary<string, object>(whereParameters.Count);
  157. StringBuilder where = new StringBuilder();
  158. int index = 0;
  159. foreach (KeyValuePair<string, object> parameter in whereParameters) {
  160. string key = parameter.Key;
  161. string value = (parameter.Value == null) ? null : parameter.Value.ToString();
  162. // exclude null and empty values.
  163. if (!(String.IsNullOrEmpty(key) || String.IsNullOrEmpty(value))) {
  164. string newKey = "@p" + index++;
  165. if (where.Length > 0) {
  166. where.Append(" AND ");
  167. }
  168. where.Append(key);
  169. where.Append(" == ");
  170. where.Append(newKey);
  171. whereClause.Parameters.Add(newKey, parameter.Value);
  172. }
  173. }
  174. whereClause.Expression = where.ToString();
  175. return whereClause;
  176. }
  177. private static string GetOrderByClause(IDictionary<string, object> orderByParameters) {
  178. Debug.Assert((orderByParameters != null) && (orderByParameters.Count > 0));
  179. StringBuilder orderBy = new StringBuilder();
  180. foreach (KeyValuePair<string, object> parameter in orderByParameters) {
  181. string value = (string)parameter.Value;
  182. // exclude null and empty values.
  183. if (!String.IsNullOrEmpty(value)) {
  184. string name = parameter.Key;
  185. //validate parameter name
  186. ValidateOrderByParameter(name, value);
  187. if (orderBy.Length > 0) {
  188. orderBy.Append(", ");
  189. }
  190. orderBy.Append(value);
  191. }
  192. }
  193. return orderBy.ToString();
  194. }
  195. internal static void ValidateOrderByParameter(string name, string value) {
  196. if (!AutoGenerateOrderByRegex.IsMatch(value)) {
  197. throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
  198. AtlasWeb.LinqDataSourceView_InvalidOrderByFieldName, value, name));
  199. }
  200. }
  201. internal static void ValidateParameterName(string name, Control owner) {
  202. if (!IdentifierRegex.IsMatch(name)) {
  203. throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
  204. AtlasWeb.LinqDataSourceView_InvalidParameterName, name, owner.ID));
  205. }
  206. }
  207. private class WhereClause {
  208. public string Expression { get; set; }
  209. public IDictionary<string, object> Parameters { get; set; }
  210. }
  211. }
  212. }