Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,40 @@
namespace System.Web.UI.WebControls.Expressions {
using System.Web.Query.Dynamic;
using System;
using System.Linq.Expressions;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections.Generic;
using System.Linq;
[
PersistChildren(false),
ParseChildren(true, "Parameters")
]
public class CustomExpression : ParameterDataSourceExpression {
private EventHandler<CustomExpressionEventArgs> _querying;
public event EventHandler<CustomExpressionEventArgs> Querying {
add {
_querying += value;
}
remove {
_querying -= value;
}
}
public override IQueryable GetQueryable(IQueryable source) {
CustomExpressionEventArgs e = new CustomExpressionEventArgs(source, GetValues());
OnQuerying(e);
return e.Query;
}
private void OnQuerying(CustomExpressionEventArgs e) {
if (_querying != null) {
_querying(this, e);
}
}
}
}

View File

@@ -0,0 +1,16 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.Linq;
using System.Security.Permissions;
using System.Collections.Generic;
public class CustomExpressionEventArgs : EventArgs {
public IQueryable Query { get; set; }
public IDictionary<string, object> Values { get; private set; }
public CustomExpressionEventArgs(IQueryable source, IDictionary<string, object> values) {
Query = source;
Values = values;
}
}
}

View File

@@ -0,0 +1,125 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public abstract class DataSourceExpression : IStateManager {
private bool _tracking;
private StateBag _viewState;
protected HttpContext Context {
get;
private set;
}
protected Control Owner {
get;
private set;
}
public IQueryableDataSource DataSource {
get;
// Internal set for unit testing
internal set;
}
protected bool IsTrackingViewState {
get {
return _tracking;
}
}
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
]
protected StateBag ViewState {
get {
if (_viewState == null) {
_viewState = new StateBag();
if (_tracking)
((IStateManager)_viewState).TrackViewState();
}
return _viewState;
}
}
protected DataSourceExpression() {
}
// internal for unit testing
internal DataSourceExpression(Control owner) {
Owner = owner;
}
public void SetDirty() {
ViewState.SetDirty(true);
}
protected virtual void LoadViewState(object savedState) {
if (savedState != null) {
((IStateManager)ViewState).LoadViewState(savedState);
}
}
protected virtual object SaveViewState() {
return (_viewState != null) ? ((IStateManager)_viewState).SaveViewState() : null;
}
protected virtual void TrackViewState() {
_tracking = true;
if (_viewState != null) {
((IStateManager)_viewState).TrackViewState();
}
}
public abstract IQueryable GetQueryable(IQueryable source);
public virtual void SetContext(Control owner, HttpContext context, IQueryableDataSource dataSource) {
if (owner == null) {
throw new ArgumentNullException("owner");
}
if (context == null) {
throw new ArgumentNullException("context");
}
if (dataSource == null) {
throw new ArgumentNullException("dataSource");
}
Owner = owner;
Context = context;
DataSource = dataSource;
}
#region IStateManager Members
bool IStateManager.IsTrackingViewState {
get {
return IsTrackingViewState;
}
}
void IStateManager.LoadViewState(object state) {
LoadViewState(state);
}
object IStateManager.SaveViewState() {
return SaveViewState();
}
void IStateManager.TrackViewState() {
TrackViewState();
}
#endregion
}
}

View File

@@ -0,0 +1,105 @@
namespace System.Web.UI.WebControls.Expressions {
using System.Collections;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Web;
using System.Web.UI;
public class DataSourceExpressionCollection : StateManagedCollection {
private IQueryableDataSource _dataSource;
private static readonly Type[] knownTypes = new Type[] {
typeof(SearchExpression),
typeof(MethodExpression),
typeof(OrderByExpression),
typeof(RangeExpression),
typeof(PropertyExpression),
typeof(CustomExpression),
};
public HttpContext Context {
get;
private set;
}
public Control Owner {
get;
private set;
}
public DataSourceExpression this[int index] {
get {
return (DataSourceExpression)((IList)this)[index];
}
set {
((IList)this)[index] = value;
}
}
// Allows for nested expression blocks to be initilaized after the fact
internal void SetContext(Control owner, HttpContext context, IQueryableDataSource dataSource) {
Owner = owner;
Context = context;
_dataSource = dataSource;
foreach (DataSourceExpression expression in this) {
expression.SetContext(owner, context, _dataSource);
}
}
public void Add(DataSourceExpression expression) {
((IList)this).Add(expression);
}
protected override object CreateKnownType(int index) {
switch (index) {
case 0:
return new SearchExpression();
case 1:
return new MethodExpression();
case 2:
return new OrderByExpression();
case 3:
return new RangeExpression();
case 4:
return new PropertyExpression();
case 5:
return new CustomExpression();
default:
throw new ArgumentOutOfRangeException("index");
}
}
public void CopyTo(DataSourceExpression[] expressionArray, int index) {
base.CopyTo(expressionArray, index);
}
public void Contains(DataSourceExpression expression) {
((IList)this).Contains(expression);
}
protected override Type[] GetKnownTypes() {
return knownTypes;
}
public int IndexOf(DataSourceExpression expression) {
return ((IList)this).IndexOf(expression);
}
public void Insert(int index, DataSourceExpression expression) {
((IList)this).Insert(index, expression);
}
public void Remove(DataSourceExpression expression) {
((IList)this).Remove(expression);
}
public void RemoveAt(int index) {
((IList)this).RemoveAt(index);
}
protected override void SetDirtyObject(object o) {
((DataSourceExpression)o).SetDirty();
}
}
}

View File

@@ -0,0 +1,109 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
internal static class ExpressionHelper {
public static Expression GetValue(Expression exp) {
Type realType = GetUnderlyingType(exp.Type);
if (realType == exp.Type) {
return exp;
}
return Expression.Convert(exp, realType);
}
public static Type GetUnderlyingType(Type type) {
// Get the type from Nullable types
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
return type.GetGenericArguments()[0];
}
return type;
}
public static object BuildObjectValue(object value, Type type) {
return System.Web.UI.WebControls.DataSourceHelper.BuildObjectValue(value, type, String.Empty);
}
public static Expression CreatePropertyExpression(Expression parameterExpression, string propertyName) {
if (parameterExpression == null) {
return null;
}
if (String.IsNullOrEmpty(propertyName)) {
return null;
}
Expression propExpression = null;
string[] props = propertyName.Split('.');
foreach (var p in props) {
if (propExpression == null) {
propExpression = Expression.PropertyOrField(parameterExpression, p);
}
else {
propExpression = Expression.PropertyOrField(propExpression, p);
}
}
return propExpression;
}
public static IQueryable Where(this IQueryable source, LambdaExpression lambda) {
return Call(source, "Where", lambda, source.ElementType);
}
public static IQueryable Call(this IQueryable source, string queryMethod, Type[] genericArgs, params Expression[] arguments) {
if (source == null) {
throw new ArgumentNullException("source");
}
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), queryMethod,
genericArgs,
arguments));
}
public static IQueryable Call(this IQueryable source, string queryableMethod, LambdaExpression lambda, params Type[] genericArgs) {
if (source == null) {
throw new ArgumentNullException("source");
}
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), queryableMethod,
genericArgs,
source.Expression, Expression.Quote(lambda)));
}
public static Expression Or(IEnumerable<Expression> expressions) {
Expression orExpression = null;
foreach (Expression e in expressions) {
if (e == null) {
continue;
}
if (orExpression == null) {
orExpression = e;
}
else {
orExpression = Expression.OrElse(orExpression, e);
}
}
return orExpression;
}
public static Expression And(IEnumerable<Expression> expressions) {
Expression andExpression = null;
foreach (Expression e in expressions) {
if (e == null) {
continue;
}
if (andExpression == null) {
andExpression = e;
}
else {
andExpression = Expression.AndAlso(andExpression, e);
}
}
return andExpression;
}
}
}

View File

@@ -0,0 +1,165 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Compilation;
using System.Web.DynamicData;
using System.Web.Resources;
using System.Web.UI.WebControls;
public class MethodExpression : ParameterDataSourceExpression {
private static readonly BindingFlags MethodFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
// We'll populate a list of ways to get the type
private Func<Type>[] typeGetters;
public string TypeName {
get {
return (string)ViewState["TypeName"] ?? String.Empty;
}
set {
ViewState["TypeName"] = value;
}
}
public string MethodName {
get {
return (string)ViewState["MethodName"] ?? String.Empty;
}
set {
ViewState["MethodName"] = value;
}
}
public bool IgnoreIfNotFound {
get {
object o = ViewState["IgnoreIfNotFound"];
return o != null ? (bool)o : false;
}
set {
ViewState["IgnoreIfNotFound"] = value;
}
}
public MethodExpression() {
// 1. If a TypeName is specified find the method on that type.
// 2. Otherwise, if the DataSource is an IDynamicDataSource, then use context type and search for the method.
// 3. Otherwise look for the method on the current TemplateControl (Page/UserControl) etc.
typeGetters = new Func<Type>[] {
() => GetType(TypeName),
() => GetType(DataSource),
() => (Owner != null && Owner.TemplateControl != null) ? Owner.TemplateControl.GetType() : null
};
}
private static Type GetType(string typeName) {
if (!String.IsNullOrEmpty(typeName)) {
return BuildManager.GetType(typeName, false /* throwOnError */, true /* ignoreCase */);
}
return null;
}
private static Type GetType(IQueryableDataSource dataSource) {
IDynamicDataSource dynamicDataSource = dataSource as IDynamicDataSource;
if (dynamicDataSource != null) {
return dynamicDataSource.ContextType;
}
return null;
}
internal MethodInfo ResolveMethod() {
if (String.IsNullOrEmpty(MethodName)) {
throw new InvalidOperationException(AtlasWeb.MethodExpression_MethodNameMustBeSpecified);
}
MethodInfo methodInfo = null;
// We allow the format string {0} in the method name
IDynamicDataSource dataSource = DataSource as IDynamicDataSource;
if (dataSource != null) {
MethodName = String.Format(CultureInfo.CurrentCulture, MethodName, dataSource.EntitySetName);
}
else if (MethodName.Contains("{0}")) {
// If method has a format string but no IDynamicDataSource then throw an exception
throw new InvalidOperationException(AtlasWeb.MethodExpression_DataSourceMustBeIDynamicDataSource);
}
foreach (Func<Type> typeGetter in typeGetters) {
Type type = typeGetter();
// If the type is null continue to next fall back function
if (type == null) {
continue;
}
methodInfo = type.GetMethod(MethodName, MethodFlags);
if (methodInfo != null) {
break;
}
}
return methodInfo;
}
public override IQueryable GetQueryable(IQueryable source) {
if (source == null) {
throw new ArgumentNullException("source");
}
MethodInfo method = ResolveMethod();
// Get the parameter values
IDictionary<string, object> parameterValues = GetValues();
if (method == null) {
if (IgnoreIfNotFound) {
// Unchange the IQueryable if the user set IgnoreIfNotFound
return source;
}
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
AtlasWeb.MethodExpression_MethodNotFound, MethodName));
}
if(!method.IsStatic) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
AtlasWeb.MethodExpression_MethodMustBeStatic, MethodName));
}
ParameterInfo[] parameterArray = method.GetParameters();
if (parameterArray.Length == 0 || !parameterArray[0].ParameterType.IsAssignableFrom(source.GetType())) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, AtlasWeb.MethodExpression_FirstParamterMustBeCorrectType,
MethodName, source.GetType()));
}
object[] arguments = new object[parameterArray.Length];
// First argument is the IQueryable
arguments[0] = source;
for (int i = 1; i < parameterArray.Length; ++i) {
ParameterInfo param = parameterArray[i];
object value;
if (!parameterValues.TryGetValue(param.Name, out value)) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
AtlasWeb.MethodExpression_ParameterNotFound, MethodName, param.Name));
}
arguments[i] = DataSourceHelper.BuildObjectValue(value, param.ParameterType, param.Name);
}
object result = method.Invoke(null, arguments);
// Require the return type be the same as the parameter type
if (result != null) {
IQueryable queryable = result as IQueryable;
// Check if the user did a projection (changed the T in IQuerable<T>)
if (queryable == null || !queryable.ElementType.IsAssignableFrom(source.ElementType)) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, AtlasWeb.MethodExpression_ChangingTheReturnTypeIsNotAllowed,
source.ElementType.FullName));
}
}
return (IQueryable)result;
}
}
}

View File

@@ -0,0 +1,82 @@
namespace System.Web.UI.WebControls.Expressions {
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Compilation;
using System.Web.Resources;
using System;
using System.Web.UI;
public class OfTypeExpression : DataSourceExpression {
private MethodInfo _ofTypeMethod;
private string _typeName;
private MethodInfo OfTypeMethod {
get {
if (_ofTypeMethod == null) {
var type = GetType(TypeName);
_ofTypeMethod = GetOfTypeMethod(type);
}
return _ofTypeMethod;
}
}
[DefaultValue("")]
public string TypeName {
get {
return _typeName ?? String.Empty;
}
set {
if (TypeName != value) {
_typeName = value;
_ofTypeMethod = null;
}
}
}
public OfTypeExpression() {
}
public OfTypeExpression(Type type) {
if (type == null) {
throw new ArgumentNullException("type");
}
TypeName = type.AssemblyQualifiedName;
_ofTypeMethod = GetOfTypeMethod(type);
}
// internal for unit testing
internal OfTypeExpression(Control owner)
: base(owner) {
}
private Type GetType(string typeName) {
if (String.IsNullOrEmpty(typeName)) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
AtlasWeb.OfTypeExpression_TypeNameNotSpecified,
Owner.ID));
}
try {
return BuildManager.GetType(typeName, true /* throwOnError */, true /* ignoreCase */);
} catch (Exception e) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
AtlasWeb.OfTypeExpression_CannotFindType,
typeName,
Owner.ID), e);
}
}
private static MethodInfo GetOfTypeMethod(Type type) {
Debug.Assert(type != null);
return typeof(Queryable).GetMethod("OfType").MakeGenericMethod(new Type[] { type });
}
public override IQueryable GetQueryable(IQueryable query) {
return query.Provider.CreateQuery(Expression.Call(null, OfTypeMethod, query.Expression));
}
}
}

View File

@@ -0,0 +1,105 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Resources;
using System.Web.UI;
[
PersistChildren(false),
ParseChildren(true, "ThenByExpressions")
]
public class OrderByExpression : DataSourceExpression {
private const string OrderByMethod = "OrderBy";
private const string ThenByMethod = "ThenBy";
private const string OrderDescendingByMethod = "OrderByDescending";
private const string ThenDescendingByMethod = "ThenByDescending";
private Collection<ThenBy> _thenByExpressions;
public string DataField {
get {
return (string)ViewState["DataField"] ?? String.Empty;
}
set {
ViewState["DataField"] = value;
}
}
public SortDirection Direction {
get {
object o = ViewState["Direction"];
return o != null ? (SortDirection)o : SortDirection.Ascending;
}
set {
ViewState["Direction"] = value;
}
}
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public Collection<ThenBy> ThenByExpressions {
get {
if (_thenByExpressions == null) {
//
_thenByExpressions = new Collection<ThenBy>();
}
return _thenByExpressions;
}
}
public override IQueryable GetQueryable(IQueryable source) {
if (source == null) {
return null;
}
if (String.IsNullOrEmpty(DataField)) {
throw new InvalidOperationException(AtlasWeb.Expressions_DataFieldRequired);
}
ParameterExpression pe = Expression.Parameter(source.ElementType, String.Empty);
source = CreateSortQueryable(source, pe, Direction, DataField, false /* isThenBy */);
foreach (ThenBy thenBy in ThenByExpressions) {
source = CreateSortQueryable(source, pe, thenBy.Direction, thenBy.DataField, true /* isThenBy */);
}
return source;
}
private static IQueryable CreateSortQueryable(IQueryable source, ParameterExpression parameterExpression, SortDirection direction, string dataField, bool isThenBy) {
string methodName = isThenBy ? GetThenBySortMethod(direction) : GetSortMethod(direction);
Expression propertyExpression = ExpressionHelper.CreatePropertyExpression(parameterExpression, dataField);
return source.Call(methodName,
Expression.Lambda(propertyExpression, parameterExpression),
source.ElementType,
propertyExpression.Type);
}
private static string GetSortMethod(SortDirection direction) {
switch (direction) {
case SortDirection.Ascending:
return OrderByMethod;
case SortDirection.Descending:
return OrderDescendingByMethod;
default:
Debug.Fail("shouldn't get here!");
return OrderByMethod;
}
}
private static string GetThenBySortMethod(SortDirection direction) {
switch (direction) {
case SortDirection.Ascending:
return ThenByMethod;
case SortDirection.Descending:
return ThenDescendingByMethod;
default:
Debug.Fail("shouldn't get here!");
return null;
}
}
}
}

View File

@@ -0,0 +1,66 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq.Expressions;
using System.Web.UI.WebControls;
[
PersistChildren(false),
ParseChildren(true, "Parameters")
]
public abstract class ParameterDataSourceExpression : DataSourceExpression {
private ParameterCollection _parameters;
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public ParameterCollection Parameters {
get {
if (_parameters == null) {
_parameters = new ParameterCollection();
_parameters.ParametersChanged += new EventHandler(OnParametersChanged);
}
return _parameters;
}
}
internal virtual IDictionary<string, object> GetValues() {
return Parameters.ToDictionary(Context, Owner);
}
public override void SetContext(Control owner, HttpContext context, IQueryableDataSource dataSource) {
base.SetContext(owner, context, dataSource);
owner.Page.LoadComplete += new EventHandler(OnPageLoadComplete);
}
private void OnParametersChanged(object sender, EventArgs e) {
if (DataSource != null) {
DataSource.RaiseViewChanged();
}
}
private void OnPageLoadComplete(object sender, System.EventArgs e) {
Parameters.UpdateValues(Context, Owner);
}
protected override object SaveViewState() {
Pair p = new Pair();
p.First = base.SaveViewState();
p.Second = DataSourceHelper.SaveViewState(_parameters);
return p;
}
protected override void LoadViewState(object savedState) {
Pair p = (Pair)savedState;
base.LoadViewState(p.First);
if (p.Second != null) {
((IStateManager)Parameters).LoadViewState(p.Second);
}
}
protected override void TrackViewState() {
base.TrackViewState();
DataSourceHelper.TrackViewState(_parameters);
}
}
}

View File

@@ -0,0 +1,42 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.Collections.Generic;
using System.Security.Permissions;
using System.Web.UI;
using System.Linq.Expressions;
using System.Linq;
public class PropertyExpression : ParameterDataSourceExpression {
public override IQueryable GetQueryable(IQueryable source) {
if (source == null) {
return null;
}
IDictionary<string, object> values = GetValues();
List<Expression> equalsExpressions = new List<Expression>();
ParameterExpression parameterExpression = Expression.Parameter(source.ElementType, String.Empty);
foreach (KeyValuePair<string, object> pair in values) {
if (!String.IsNullOrEmpty(pair.Key)) {
// Create the property expression
Expression property = ExpressionHelper.CreatePropertyExpression(parameterExpression, pair.Key);
// Get the value
object value = ExpressionHelper.BuildObjectValue(pair.Value, property.Type);
// Create Property == Value and '&&' the expressions together
if (value != null) {
Expression valueExpression = Expression.Constant(value, property.Type);
Expression equalsExpression = Expression.Equal(property, valueExpression);
equalsExpressions.Add(equalsExpression);
}
}
}
if (equalsExpressions.Any()) {
Expression body = ExpressionHelper.And(equalsExpressions);
return ExpressionHelper.Where(source, Expression.Lambda(body, parameterExpression));
}
return source;
}
}
}

View File

@@ -0,0 +1,53 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using System.Web.UI;
[
ParseChildren(true, "Expressions"),
PersistChildren(false)
]
public class QueryExpression {
private HttpContext _context;
private Control _owner;
private IQueryableDataSource _dataSource;
private DataSourceExpressionCollection _expressions;
[
PersistenceMode(PersistenceMode.InnerDefaultProperty)
]
public DataSourceExpressionCollection Expressions {
get {
if (_expressions == null) {
_expressions = new DataSourceExpressionCollection();
}
return _expressions;
}
}
public void Initialize(Control owner, HttpContext context, IQueryableDataSource dataSource) {
_owner = owner;
_context = context;
_dataSource = dataSource;
Expressions.SetContext(owner, context, dataSource);
}
public virtual IQueryable GetQueryable(IQueryable source) {
if (source == null) {
return null;
}
foreach (DataSourceExpression e in Expressions) {
source = e.GetQueryable(source) ?? source;
}
return source;
}
}
}

View File

@@ -0,0 +1,144 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Resources;
using System.Web.UI;
using System.Web.UI.WebControls;
public class RangeExpression : ParameterDataSourceExpression {
public string DataField {
get {
return (string)ViewState["DataField"] ?? String.Empty;
}
set {
ViewState["DataField"] = value;
}
}
public RangeType MinType {
get {
object o = ViewState["MinType"];
return o != null ? (RangeType)o : RangeType.None;
}
set {
ViewState["MinType"] = value;
}
}
public RangeType MaxType {
get {
object o = ViewState["MaxType"];
return o != null ? (RangeType)o : RangeType.None;
}
set {
ViewState["MaxType"] = value;
}
}
internal virtual new IOrderedDictionary GetValues() {
return Parameters.GetValues(Context, Owner);
}
public override IQueryable GetQueryable(IQueryable source) {
if (source == null) {
return null;
}
if (String.IsNullOrEmpty(DataField)) {
throw new InvalidOperationException(AtlasWeb.Expressions_DataFieldRequired);
}
IOrderedDictionary values = GetValues();
ParameterExpression parameterExpression = Expression.Parameter(source.ElementType, String.Empty);
Expression properyExpression = ExpressionHelper.GetValue(ExpressionHelper.CreatePropertyExpression(parameterExpression, DataField));
if (MinType == RangeType.None && MaxType == RangeType.None) {
throw new InvalidOperationException(AtlasWeb.RangeExpression_RangeTypeMustBeSpecified);
}
Expression minExpression = null;
Expression maxExpression = null;
if (MinType != RangeType.None) {
if (values.Count == 0) {
throw new InvalidOperationException(AtlasWeb.RangeExpression_MinimumValueRequired);
}
if (values[0] != null) {
minExpression = GetMinRangeExpression(properyExpression, values[0], MinType);
}
}
if (MaxType != RangeType.None) {
if (values.Count == 0 || ((minExpression != null) && (values.Count == 1))) {
throw new InvalidOperationException(AtlasWeb.RangeExpression_MaximumValueRequired);
}
object maxValue = minExpression == null ? values[0] : values[1];
if (maxValue != null) {
maxExpression = GetMaxRangeExpression(properyExpression, maxValue, MaxType);
}
}
if ((maxExpression == null) && (minExpression == null)) {
return null;
}
Expression rangeExpression = CreateRangeExpressionBody(minExpression, maxExpression);
return ExpressionHelper.Where(source, Expression.Lambda(rangeExpression, parameterExpression));
}
private static Expression GetMinRangeExpression(Expression propertyExpression, object value, RangeType rangeType) {
ConstantExpression constantValue = Expression.Constant(ExpressionHelper.BuildObjectValue(value, propertyExpression.Type));
switch (rangeType) {
case RangeType.Exclusive:
return Expression.GreaterThan(propertyExpression, constantValue);
case RangeType.None:
return null;
case RangeType.Inclusive:
return Expression.GreaterThanOrEqual(propertyExpression, constantValue);
default:
Debug.Fail("shouldn't get here!");
return null;
}
}
private static Expression GetMaxRangeExpression(Expression propertyExpression, object value, RangeType rangeType) {
ConstantExpression constantValue = Expression.Constant(ExpressionHelper.BuildObjectValue(value, propertyExpression.Type));
switch (rangeType) {
case RangeType.Exclusive:
return Expression.LessThan(propertyExpression, constantValue);
case RangeType.None:
return null;
case RangeType.Inclusive:
return Expression.LessThanOrEqual(propertyExpression, constantValue);
default:
Debug.Fail("shouldn't get here!");
return null;
}
}
private static Expression CreateRangeExpressionBody(Expression minExpression, Expression maxExpression) {
if (minExpression == null && maxExpression == null) {
return null;
}
if (minExpression == null) {
return maxExpression;
}
if (maxExpression == null) {
return minExpression;
}
return Expression.AndAlso(minExpression, maxExpression);
}
}
}

View File

@@ -0,0 +1,9 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
public enum RangeType {
None,
Exclusive,
Inclusive
}
}

View File

@@ -0,0 +1,90 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Resources;
using System.Web.UI;
using System.Web.UI.WebControls;
public class SearchExpression : ParameterDataSourceExpression {
public string DataFields {
get {
return (string)ViewState["DataFields"] ?? String.Empty;
}
set {
ViewState["DataFields"] = value;
}
}
public SearchType SearchType {
get {
object o = ViewState["SearchType"];
return o != null ? (SearchType)o : SearchType.StartsWith;
}
set {
ViewState["SearchType"] = value;
}
}
public StringComparison ComparisonType {
get {
object o = ViewState["ComparisonType"];
return o != null ? (StringComparison)o : StringComparison.OrdinalIgnoreCase;
}
set {
ViewState["ComparisonType"] = value;
}
}
public override IQueryable GetQueryable(IQueryable source) {
if (source == null) {
return null;
}
if ((DataFields == null) || String.IsNullOrEmpty(DataFields.Trim())) {
throw new InvalidOperationException(AtlasWeb.Expressions_DataFieldRequired);
}
IDictionary<string, object> values = GetValues();
if (values.Count == 0) {
throw new InvalidOperationException(AtlasWeb.SearchExpression_ParameterRequired);
}
string query = Convert.ToString(values.First().Value, CultureInfo.CurrentCulture);
if (String.IsNullOrEmpty(query)) {
return null;
}
string[] properties = DataFields.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
// Use the or expression to or the fields together
List<Expression> searchExpressions = new List<Expression>();
ParameterExpression parameterExpression = Expression.Parameter(source.ElementType, String.Empty);
foreach (string p in properties) {
Expression property = ExpressionHelper.CreatePropertyExpression(parameterExpression, p.Trim());
searchExpressions.Add(CreateCallExpression(property, query));
}
return ExpressionHelper.Where(source,
Expression.Lambda(ExpressionHelper.Or(searchExpressions),
parameterExpression));
}
private Expression CreateCallExpression(Expression property, string query) {
// LINQ to SQL does not support the overloads StartsWith(string, StringComparer) or EndsWith(string, StringComparer)
// and Contains has not overload that takes a StringComparer
if (SearchType == SearchType.Contains || (ViewState["ComparisonType"] == null)) {
return Expression.Call(property, SearchType.ToString(), Type.EmptyTypes, Expression.Constant(query, property.Type));
}
return Expression.Call(property, SearchType.ToString(), Type.EmptyTypes, Expression.Constant(query, property.Type), Expression.Constant(ComparisonType));
}
}
}

View File

@@ -0,0 +1,9 @@
namespace System.Web.UI.WebControls.Expressions {
using System;
public enum SearchType {
Contains,
StartsWith,
EndsWith
}
}

View File

@@ -0,0 +1,16 @@
namespace System.Web.UI.WebControls.Expressions {
using System.Web.UI.WebControls;
using System.Security.Permissions;
public class ThenBy {
public string DataField {
get;
set;
}
public SortDirection Direction {
get;
set;
}
}
}