ObjectDataSourceView.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / UI / WebControls / ObjectDataSourceView.cs / 2 / ObjectDataSourceView.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI.WebControls { 
 
    using System;
    using System.Collections; 
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Data;
    using System.Globalization; 
    using System.Reflection;
    using System.Security; 
    using System.Security.Permissions; 
    using System.Text;
    using System.Web.Compilation; 
    using System.Web.UI;
    using System.Web.Util;

    using ConflictOptions = System.Web.UI.ConflictOptions; 

 
    ///  
    /// Represents a single view of an ObjectDataSource.
    ///  
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class ObjectDataSourceView : DataSourceView, IStateManager {
 
        private static readonly object EventDeleted = new object();
        private static readonly object EventDeleting = new object(); 
        private static readonly object EventFiltering = new object(); 
        private static readonly object EventInserted = new object();
        private static readonly object EventInserting = new object(); 
        private static readonly object EventObjectCreated = new object();
        private static readonly object EventObjectCreating = new object();
        private static readonly object EventObjectDisposing = new object();
        private static readonly object EventSelected = new object(); 
        private static readonly object EventSelecting = new object();
        private static readonly object EventUpdated = new object(); 
        private static readonly object EventUpdating = new object(); 

        private HttpContext _context; 
        private ObjectDataSource _owner;
        private bool _tracking;

        private ConflictOptions _conflictDetection = ConflictOptions.OverwriteChanges; 
        private bool _convertNullToDBNull;
        private string _dataObjectTypeName; 
        private string _deleteMethod; 
        private ParameterCollection _deleteParameters;
        private bool _enablePaging; 
        private string _filterExpression;
        private ParameterCollection _filterParameters;
        private string _insertMethod;
        private ParameterCollection _insertParameters; 
        private string _maximumRowsParameterName;
        private string _oldValuesParameterFormatString; 
        private string _selectCountMethod; 
        private string _selectMethod;
        private ParameterCollection _selectParameters; 
        private string _sortParameterName;
        private string _startRowIndexParameterName;
        private string _typeName;
        private string _updateMethod; 
        private ParameterCollection _updateParameters;
 
 
        /// 
        /// Creates a new ObjectDataSourceView. 
        /// 
        public ObjectDataSourceView(ObjectDataSource owner, string name, HttpContext context)
            : base(owner, name) {
            Debug.Assert(owner != null); 
            _owner = owner;
            _context = context; 
        } 

 

        /// 
        /// Indicates that the view can delete rows.
        ///  
        public override bool CanDelete {
            get { 
                return (DeleteMethod.Length != 0); 
            }
        } 


        /// 
        /// Indicates that the view can add new rows. 
        /// 
        public override bool CanInsert { 
            get { 
                return (InsertMethod.Length != 0);
            } 
        }

        /// 
        /// Indicates that the view can do server paging. 
        /// 
        public override bool CanPage { 
            get { 
                return EnablePaging;
            } 
        }

        /// 
        /// Indicates that the view can return the total number of rows returned by the query. 
        /// 
        public override bool CanRetrieveTotalRowCount { 
            get { 
                // We don't necessarily know if the data source can get the total row count until after the SelectMethod has
                // been executed (e.g. it might return a DataSet). If the SelectCountMethod is set, we can definitely 
                // get the count. However, if it is not, we can only get the row count from the Selected data if it was not
                // paged by the user's object, and it happened to be a DataView, DataSet, DataTable, ICollection, or object.
                return ((SelectCountMethod.Length > 0) || (!EnablePaging));
            } 
        }
 
 
        /// 
        /// Indicates that the view can sort rows. 
        /// 
        public override bool CanSort {
            get {
                // We don't really know if the data source can sort until after the SelectMethod has 
                // been executed (e.g. it might return a DataSet), so we just assume it's true.
                return true; 
                //return (SortParameterName.Length > 0); 
            }
        } 


        /// 
        /// Indicates that the view can update rows. 
        /// 
        public override bool CanUpdate { 
            get { 
                return (UpdateMethod.Length != 0);
            } 
        }

        /// 
        /// Whether the delete command passes old values in the parameter collection. 
        /// 
        public ConflictOptions ConflictDetection { 
            get { 
                return _conflictDetection;
            } 
            set {
                if ((value < ConflictOptions.OverwriteChanges) || (value > ConflictOptions.CompareAllValues)) {
                    throw new ArgumentOutOfRangeException("value");
                } 
                _conflictDetection = value;
                OnDataSourceViewChanged(EventArgs.Empty); 
            } 
        }
 
        /// 
        /// Whether null values passed into insert/update/delete operations
        /// will be converted to System.DbNull.
        ///  
        public bool ConvertNullToDBNull {
            get { 
                return _convertNullToDBNull; 
            }
            set { 
                _convertNullToDBNull = value;
            }
        }
 

        ///  
        /// An optional type that is used for update, insert, and delete 
        /// scenarios where the object's methods take in an aggregate object
        /// rather than one parameter for each property in the selected data. 
        /// 
        public string DataObjectTypeName {
            get {
                if (_dataObjectTypeName == null) { 
                    return String.Empty;
                } 
                return _dataObjectTypeName; 
            }
            set { 
                if (DataObjectTypeName != value) {
                    _dataObjectTypeName = value;
                    OnDataSourceViewChanged(EventArgs.Empty);
                } 
            }
        } 
 

        ///  
        /// The method to execute when Delete() is called.
        /// 
        public string DeleteMethod {
            get { 
                if (_deleteMethod == null) {
                    return String.Empty; 
                } 
                return _deleteMethod;
            } 
            set {
                _deleteMethod = value;
            }
        } 

        ///  
        // Collection of parameters used when calling the DeleteMethod. These parameters are merged with the parameters provided by data-bound controls. 

        ///  
        public ParameterCollection DeleteParameters {
            get {
                if (_deleteParameters == null) {
                    _deleteParameters = new ParameterCollection(); 
                }
                return _deleteParameters; 
            } 
        }
 
        /// 
        /// Indicates whether the Select method supports paging. If this is set to true, the
        /// StartRowIndexParameterName and MaximumRowsParameterName properties must be set to the
        /// names of the parameters of the Select method that accept the values for the starting 
        /// record to retrieve and the number of records to retrieve.
        ///  
        public bool EnablePaging { 
            get {
                return _enablePaging; 
            }
            set {
                if (EnablePaging != value) {
                    _enablePaging = value; 
                    OnDataSourceViewChanged(EventArgs.Empty);
                } 
            } 
        }
 

        /// 
        /// Filter expression used when Select() is called. Filtering is only available when the SelectMethod returns a DataSet or a DataTable.
        ///  
        public string FilterExpression {
            get { 
                if (_filterExpression == null) { 
                    return String.Empty;
                } 
                return _filterExpression;
            }
            set {
                if (FilterExpression != value) { 
                    _filterExpression = value;
                    OnDataSourceViewChanged(EventArgs.Empty); 
                } 
            }
        } 


        /// 
        /// Collection of parameters used in the FilterExpression property. Filtering is only available when the SelectMethod returns a DataSet or a DataTable. 
        /// 
        public ParameterCollection FilterParameters { 
            get { 
                if (_filterParameters == null) {
                    _filterParameters = new ParameterCollection(); 

                    _filterParameters.ParametersChanged += new EventHandler(SelectParametersChangedEventHandler);

                    if (_tracking) { 
                        ((IStateManager)_filterParameters).TrackViewState();
                    } 
                } 
                return _filterParameters;
            } 
        }


        ///  
        /// The method to execute when Insert() is called.
        ///  
        public string InsertMethod { 
            get {
                if (_insertMethod == null) { 
                    return String.Empty;
                }
                return _insertMethod;
            } 
            set {
                _insertMethod = value; 
            } 
        }
 

        /// 
        /// Collection of values used when calling the InsertMethod. These parameters are merged with the parameters provided by data-bound controls.
        ///  
        public ParameterCollection InsertParameters {
            get { 
                if (_insertParameters == null) { 
                    _insertParameters = new ParameterCollection();
                } 
                return _insertParameters;
            }
        }
 
        /// 
        /// Returns whether this object is tracking view state. 
        ///  
        protected bool IsTrackingViewState {
            get { 
                return _tracking;
            }
        }
 
        /// 
        /// When EnablePaging is set to true, this property indicates the parameter of the Select 
        /// method that accepts the value for the number of records to retrieve. 
        /// 
        public string MaximumRowsParameterName { 
            get {
                if (_maximumRowsParameterName == null) {
                    return "maximumRows";
                } 
                return _maximumRowsParameterName;
            } 
            set { 
                if (MaximumRowsParameterName != value) {
                    _maximumRowsParameterName = value; 
                    OnDataSourceViewChanged(EventArgs.Empty);
                }
            }
        } 

        ///  
        /// The format string applied to the names of the old values parameters 
        /// 
        [ 
        DefaultValue("{0}"),
        WebCategory("Data"),
        WebSysDescription(SR.DataSource_OldValuesParameterFormatString),
        ] 
        public string OldValuesParameterFormatString {
            get { 
                if (_oldValuesParameterFormatString == null) { 
                    return "{0}";
                } 
                return _oldValuesParameterFormatString;
            }
            set {
                _oldValuesParameterFormatString = value; 
                OnDataSourceViewChanged(EventArgs.Empty);
            } 
        } 

        ///  
        /// The method to execute when the total row count is needed. This method is only
        /// used when EnablePaging is true and is optional.
        /// 
        public string SelectCountMethod { 
            get {
                if (_selectCountMethod == null) { 
                    return String.Empty; 
                }
                return _selectCountMethod; 
            }
            set {
                if (SelectCountMethod != value) {
                    _selectCountMethod = value; 
                    OnDataSourceViewChanged(EventArgs.Empty);
                } 
            } 
        }
 
        /// 
        /// The method to execute when Select() is called.
        /// 
        public string SelectMethod { 
            get {
                if (_selectMethod == null) { 
                    return String.Empty; 
                }
                return _selectMethod; 
            }
            set {
                if (SelectMethod != value) {
                    _selectMethod = value; 
                    OnDataSourceViewChanged(EventArgs.Empty);
                } 
            } 
        }
 
        /// 
        /// Collection of parameters used when calling the SelectMethod.
        /// 
        public ParameterCollection SelectParameters { 
            get {
                if (_selectParameters == null) { 
                    _selectParameters = new ParameterCollection(); 

                    _selectParameters.ParametersChanged += new EventHandler(SelectParametersChangedEventHandler); 

                    if (_tracking) {
                        ((IStateManager)_selectParameters).TrackViewState();
                    } 
                }
                return _selectParameters; 
            } 
        }
 
        /// 
        /// The name of the parameter in the SelectMethod that specifies the
        /// sort expression. This parameter's value will be automatically set
        /// at runtime with the appropriate sort expression. 
        /// 
        public string SortParameterName { 
            get { 
                if (_sortParameterName == null) {
                    return String.Empty; 
                }
                return _sortParameterName;
            }
            set { 
                if (SortParameterName != value) {
                    _sortParameterName = value; 
                    OnDataSourceViewChanged(EventArgs.Empty); 
                }
            } 
        }

        /// 
        /// When EnablePaging is set to true, this property indicates the parameter of the Select 
        /// method that accepts the value for the number of first record to retrieve.
        ///  
        public string StartRowIndexParameterName { 
            get {
                if (_startRowIndexParameterName == null) { 
                    return "startRowIndex";
                }
                return _startRowIndexParameterName;
            } 
            set {
                if (StartRowIndexParameterName != value) { 
                    _startRowIndexParameterName = value; 
                    OnDataSourceViewChanged(EventArgs.Empty);
                } 
            }
        }

        ///  
        /// The type that contains the methods specified in this control.
        ///  
        public string TypeName { 
            get {
                if (_typeName == null) { 
                    return String.Empty;
                }
                return _typeName;
            } 
            set {
                if (TypeName != value) { 
                    _typeName = value; 
                    OnDataSourceViewChanged(EventArgs.Empty);
                } 
            }
        }

        ///  
        /// The method to execute when Update() is called.
        ///  
        public string UpdateMethod { 
            get {
                if (_updateMethod == null) { 
                    return String.Empty;
                }
                return _updateMethod;
            } 
            set {
                _updateMethod = value; 
            } 
        }
 
        /// 
        /// Collection of parameters and values used when calling the UpdateMethod. These parameters are merged with the parameters provided by data-bound controls.
        /// 
        public ParameterCollection UpdateParameters { 
            get {
                if (_updateParameters == null) { 
                    _updateParameters = new ParameterCollection(); 
                }
                return _updateParameters; 
            }
        }

 
        /// 
        /// This event is raised after the Delete operation has completed. 
        /// Handle this event if you need to examine the return values of 
        /// the method call, or examine an exception that may have been thrown.
        ///  
        public event ObjectDataSourceStatusEventHandler Deleted {
            add {
                Events.AddHandler(EventDeleted, value);
            } 
            remove {
                Events.RemoveHandler(EventDeleted, value); 
            } 
        }
 
        /// 
        /// This event is raised before the Delete operation has been executed.
        /// Handle this event if you need to validate the values of parameters or
        /// change their values. 
        /// 
        public event ObjectDataSourceMethodEventHandler Deleting { 
            add { 
                Events.AddHandler(EventDeleting, value);
            } 
            remove {
                Events.RemoveHandler(EventDeleting, value);
            }
        } 

        public event ObjectDataSourceFilteringEventHandler Filtering { 
            add { 
                Events.AddHandler(EventFiltering, value);
            } 
            remove {
                Events.RemoveHandler(EventFiltering, value);
            }
        } 

        ///  
        /// This event is raised after the Insert operation has completed. 
        /// Handle this event if you need to examine the return values of
        /// the method call, or examine an exception that may have been thrown. 
        /// 
        public event ObjectDataSourceStatusEventHandler Inserted {
            add {
                Events.AddHandler(EventInserted, value); 
            }
            remove { 
                Events.RemoveHandler(EventInserted, value); 
            }
        } 

        /// 
        /// This event is raised before the Insert operation has been executed.
        /// Handle this event if you need to validate the values of parameters or 
        /// change their values.
        ///  
        public event ObjectDataSourceMethodEventHandler Inserting { 
            add {
                Events.AddHandler(EventInserting, value); 
            }
            remove {
                Events.RemoveHandler(EventInserting, value);
            } 
        }
 
        ///  
        /// This event is raised after the instance of the object has been created.
        /// Handle this event if you need to set additional properties on the 
        /// object before any other methods are called. This event will not be
        /// raised if a custom instance was provided in the ObjectCreating event.
        /// 
        public event ObjectDataSourceObjectEventHandler ObjectCreated { 
            add {
                Events.AddHandler(EventObjectCreated, value); 
            } 
            remove {
                Events.RemoveHandler(EventObjectCreated, value); 
            }
        }

        ///  
        /// This event is raised before the instance of the object has been created.
        /// Handle this event if you need to call a non-default constructor on the 
        /// object. Set the ObjectInstance property of the EventArgs with the 
        /// custom instance. If this is set, the ObjectCreated event will not be
        /// raised. 
        /// 
        public event ObjectDataSourceObjectEventHandler ObjectCreating {
            add {
                Events.AddHandler(EventObjectCreating, value); 
            }
            remove { 
                Events.RemoveHandler(EventObjectCreating, value); 
            }
        } 

        /// 
        /// This event is raised before the instance of the object is disposed.
        /// Handle this event if you need to retrieve properties on the 
        /// object before it is disposed. If the object implements the IDispoable
        /// interface, then the Dispose() method will be called automatically. 
        /// Set the Cancel property of the event args to true if you do not want 
        /// IDisposable.Dispose() to be called automatically.
        ///  
        public event ObjectDataSourceDisposingEventHandler ObjectDisposing {
            add {
                Events.AddHandler(EventObjectDisposing, value);
            } 
            remove {
                Events.RemoveHandler(EventObjectDisposing, value); 
            } 
        }
 
        /// 
        /// This event is raised after the Select operation has completed.
        /// Handle this event if you need to examine the return values of
        /// the method call, or examine an exception that may have been thrown. 
        /// 
        public event ObjectDataSourceStatusEventHandler Selected { 
            add { 
                Events.AddHandler(EventSelected, value);
            } 
            remove {
                Events.RemoveHandler(EventSelected, value);
            }
        } 

        ///  
        /// This event is raised before the Select operation has been executed. 
        /// Handle this event if you need to validate the values of parameters or
        /// change their values. 
        /// 
        public event ObjectDataSourceSelectingEventHandler Selecting {
            add {
                Events.AddHandler(EventSelecting, value); 
            }
            remove { 
                Events.RemoveHandler(EventSelecting, value); 
            }
        } 

        /// 
        /// This event is raised after the Update operation has completed.
        /// Handle this event if you need to examine the return values of 
        /// the method call, or examine an exception that may have been thrown.
        ///  
        public event ObjectDataSourceStatusEventHandler Updated { 
            add {
                Events.AddHandler(EventUpdated, value); 
            }
            remove {
                Events.RemoveHandler(EventUpdated, value);
            } 
        }
 
        ///  
        /// This event is raised before the Update operation has been executed.
        /// Handle this event if you need to validate the values of parameters or 
        /// change their values.
        /// 
        public event ObjectDataSourceMethodEventHandler Updating {
            add { 
                Events.AddHandler(EventUpdating, value);
            } 
            remove { 
                Events.RemoveHandler(EventUpdating, value);
            } 
        }


        ///  
        /// Creates a data object and sets the properties specified by name/value
        /// pairs in the dictionary. 
        ///  
        private object BuildDataObject(Type dataObjectType, IDictionary inputParameters) {
            Debug.Assert(inputParameters != null, "Did not expect null parameter dictionary"); 
            Debug.Assert(dataObjectType != null, "Did not expect null DataObjectType");

            object dataObject = Activator.CreateInstance(dataObjectType);
 
            Debug.Assert(dataObject != null, "We should never get back a null instance of the DataObject if the creation succeeded.");
 
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(dataObject); 
            foreach (DictionaryEntry de in inputParameters) {
                // 
                string propName = (de.Key == null ? String.Empty : de.Key.ToString());
                PropertyDescriptor pd = props.Find(propName, true);
                if (pd == null) {
                    throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_DataObjectPropertyNotFound, propName, _owner.ID)); 
                }
                if (pd.IsReadOnly) { 
                    throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_DataObjectPropertyReadOnly, propName, _owner.ID)); 
                }
                object value = BuildObjectValue(de.Value, pd.PropertyType, propName); 
                pd.SetValue(dataObject, value);
            }

            return dataObject; 
        }
 
        ///  
        /// Builds a strongly typed value to be passed into a method either as a parameter
        /// or as part of a data object. This will attempt to perform appropriate type 
        /// conversions based on the destination type and throw exceptions on fatal errors.
        /// 
        private static object BuildObjectValue(object value, Type destinationType, string paramName) {
            // Only consider converting the type if the value is non-null and the types don't match 
            if (value != null && (!destinationType.IsInstanceOfType(value))) {
                Type innerDestinationType = destinationType; 
                bool isNullable = false; 
                if (destinationType.IsGenericType && (destinationType.GetGenericTypeDefinition() == typeof(Nullable<>))) {
                    innerDestinationType = destinationType.GetGenericArguments()[0]; 
                    isNullable = true;
                }
                else {
                    if (destinationType.IsByRef) { 
                        innerDestinationType = destinationType.GetElementType();
                    } 
                } 

                // Try to convert from for example string to DateTime, so that 
                // afterwards we can convert DateTime to Nullable

                // If the value is a string, we attempt to use a TypeConverter to convert it
                value = ConvertType(value, innerDestinationType, paramName); 

                // Special-case the value when the destination is Nullable 
                if (isNullable) { 
                    Type paramValueType = value.GetType();
                    if (innerDestinationType != paramValueType) { 
                        // Throw if for example, we are trying to convert from int to Nullable
                        throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_CannotConvertType, paramName, paramValueType.FullName, String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", destinationType.GetGenericArguments()[0].FullName)));
                    }
                } 
            }
            return value; 
        } 

        ///  
        /// Converts a type from a string representation to a strong type using
        /// an appropriate TypeConverter. If the value is not a string, the value
        /// is left unchanged.
        ///  
        private static object ConvertType(object value, Type type, string paramName) {
            string s = value as string; 
            if (s != null) { 
                // Get the type converter for the destination type
                TypeConverter converter = TypeDescriptor.GetConverter(type); 
                Debug.Assert(converter != null);
                if (converter != null) {
                    // Perform the conversion
                    try { 
                        value = converter.ConvertFromInvariantString(s);
                    } 
                    catch (NotSupportedException) { 
                        throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_CannotConvertType, paramName, typeof(string).FullName, type.FullName));
                    } 
                    catch (FormatException) {
                        throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_CannotConvertType, paramName, typeof(string).FullName, type.FullName));
                    }
                } 
            }
            return value; 
        } 

        ///  
        /// Creates an IEnumerable from the given data object and validates that the
        /// DataSourceSelectArguments are valid for the conditions.
        /// 
        private IEnumerable CreateEnumerableData(object dataObject, DataSourceSelectArguments arguments) { 
            if (FilterExpression.Length > 0) {
                // Since this type is not valid for filtering, throw if there is a filter 
                throw new NotSupportedException(SR.GetString(SR.ObjectDataSourceView_FilterNotSupported, _owner.ID)); 
            }
 
            if (!String.IsNullOrEmpty(arguments.SortExpression)) {
                throw new NotSupportedException(SR.GetString(SR.ObjectDataSourceView_SortNotSupportedOnIEnumerable, _owner.ID));
            }
 
            IEnumerable enumerable = dataObject as IEnumerable;
            if (enumerable != null) { 
                // If object is an IEnumerable, return it as it is 
                if (!EnablePaging && arguments.RetrieveTotalRowCount && SelectCountMethod.Length == 0) {
                    ICollection collection = enumerable as ICollection; 
                    if (collection != null) {
                        arguments.TotalRowCount = collection.Count;
                    }
                } 

                return enumerable; 
            } 
            else {
                // The result is neither a DataView, DataSet, DataTable, nor an IEnumerable, so we just wrap it in an IEnumerable 
                if (arguments.RetrieveTotalRowCount && SelectCountMethod.Length == 0) {
                    arguments.TotalRowCount = 1;
                }
 
                return new object[1] { dataObject };
            } 
        } 

        ///  
        /// Creates a filtered DataView with optional filtering.
        /// 
        private IEnumerable CreateFilteredDataView(DataTable dataTable, string sortExpression, string filterExpression) {
            IOrderedDictionary parameterValues = FilterParameters.GetValues(_context, _owner); 
            if (filterExpression.Length > 0) {
                ObjectDataSourceFilteringEventArgs filterArgs = new ObjectDataSourceFilteringEventArgs(parameterValues); 
                OnFiltering(filterArgs); 
                if (filterArgs.Cancel) {
                    return null; 
                }
            }
            return FilteredDataSetHelper.CreateFilteredDataView(dataTable, sortExpression, filterExpression, parameterValues);
        } 

        public int Delete(IDictionary keys, IDictionary oldValues) { 
            return ExecuteDelete(keys, oldValues); 
        }
 
        /// 
        /// 
        protected override int ExecuteDelete(IDictionary keys, IDictionary oldValues) {
            if (!CanDelete) { 
                throw new NotSupportedException(SR.GetString(SR.ObjectDataSourceView_DeleteNotSupported, _owner.ID));
            } 
 
            Type type = GetType(TypeName);
            Debug.Assert(type != null, "Should not have a null type at this point"); 

            // Try to get the DataObject type. If we do get the type then we will construct
            // DataObjects representing the old values.
            Type dataObjectType = TryGetDataObjectType(); 

            ObjectDataSourceMethod method; 
 
            if (dataObjectType != null) {
                // Build DataObject (Old) 
                IDictionary caseInsensitiveOldValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);

                MergeDictionaries(DeleteParameters, keys, caseInsensitiveOldValues);
 
                if (ConflictDetection == ConflictOptions.CompareAllValues) {
                    if (oldValues == null) { 
                        throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_Pessimistic, SR.GetString(SR.DataSourceView_delete), _owner.ID, "oldValues")); 
                    }
                    MergeDictionaries(DeleteParameters, oldValues, caseInsensitiveOldValues); 
                }

                object oldDataObject = BuildDataObject(dataObjectType, caseInsensitiveOldValues);
 

                // Resolve and invoke the method 
                method = GetResolvedMethodData(type, DeleteMethod, dataObjectType, oldDataObject, null, DataSourceOperation.Delete); 

                ObjectDataSourceMethodEventArgs eventArgs = new ObjectDataSourceMethodEventArgs(method.Parameters); 
                OnDeleting(eventArgs);
                if (eventArgs.Cancel) {
                    return 0;
                } 
            }
            else { 
                // Build parameter list that contains old values 
                IOrderedDictionary caseInsensitiveAllValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
 
                string oldValuesParameterFormatString = OldValuesParameterFormatString;

                MergeDictionaries(DeleteParameters, DeleteParameters.GetValues(_context, _owner), caseInsensitiveAllValues);
                MergeDictionaries(DeleteParameters, keys, caseInsensitiveAllValues, oldValuesParameterFormatString); 

                if (ConflictDetection == ConflictOptions.CompareAllValues) { 
                    if (oldValues == null) { 
                        throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_Pessimistic, SR.GetString(SR.DataSourceView_delete), _owner.ID, "oldValues"));
                    } 
                    MergeDictionaries(DeleteParameters, oldValues, caseInsensitiveAllValues, oldValuesParameterFormatString);
                }

                ObjectDataSourceMethodEventArgs eventArgs = new ObjectDataSourceMethodEventArgs(caseInsensitiveAllValues); 
                OnDeleting(eventArgs);
                if (eventArgs.Cancel) { 
                    return 0; 
                }
 
                // Resolve and invoke the method
                method = GetResolvedMethodData(type, DeleteMethod, caseInsensitiveAllValues, DataSourceOperation.Delete);
            }
 
            ObjectDataSourceResult result = InvokeMethod(method);
 
            // Invalidate the cache and raise the change event to notify bound controls 
            if (_owner.Cache.Enabled) {
                _owner.InvalidateCacheEntry(); 
            }
            OnDataSourceViewChanged(EventArgs.Empty);

            return result.AffectedRows; 
        }
 
        ///  
        /// 
        protected override int ExecuteInsert(IDictionary values) { 
            if (!CanInsert) {
                throw new NotSupportedException(SR.GetString(SR.ObjectDataSourceView_InsertNotSupported, _owner.ID));
            }
 
            Type type = GetType(TypeName);
            Debug.Assert(type != null, "Should not have a null type at this point"); 
 
            // Try to get the DataObject type. If we do get the type then we will construct
            // DataObjects representing the new values. 
            Type dataObjectType = TryGetDataObjectType();

            ObjectDataSourceMethod method;
 
            if (dataObjectType != null) {
                // Build DataObject (New) 
                if (values == null || values.Count == 0) { 
                    throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_InsertRequiresValues, _owner.ID));
                } 

                IDictionary caseInsensitiveNewValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);

                MergeDictionaries(InsertParameters, values, caseInsensitiveNewValues); 

                object newDataObject = BuildDataObject(dataObjectType, caseInsensitiveNewValues); 
 
                // Resolve and invoke the method
                method = GetResolvedMethodData(type, InsertMethod, dataObjectType, null, newDataObject, DataSourceOperation.Insert); 

                ObjectDataSourceMethodEventArgs eventArgs = new ObjectDataSourceMethodEventArgs(method.Parameters);
                OnInserting(eventArgs);
                if (eventArgs.Cancel) { 
                    return 0;
                } 
            } 
            else {
                // Build parameter list that contains new values 

                IOrderedDictionary caseInsensitiveAllValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);

                MergeDictionaries(InsertParameters, InsertParameters.GetValues(_context, _owner), caseInsensitiveAllValues); 
                MergeDictionaries(InsertParameters, values, caseInsensitiveAllValues);
 
                ObjectDataSourceMethodEventArgs eventArgs = new ObjectDataSourceMethodEventArgs(caseInsensitiveAllValues); 
                OnInserting(eventArgs);
                if (eventArgs.Cancel) { 
                    return 0;
                }

                // Resolve and invoke the method 
                method = GetResolvedMethodData(type, InsertMethod, caseInsensitiveAllValues, DataSourceOperation.Insert);
            } 
 
            ObjectDataSourceResult result = InvokeMethod(method);
 
            // Invalidate the cache and raise the change event to notify bound controls
            if (_owner.Cache.Enabled) {
                _owner.InvalidateCacheEntry();
            } 
            OnDataSourceViewChanged(EventArgs.Empty);
 
            return result.AffectedRows; 
        }
 
        /// 
        /// 
        protected internal override IEnumerable ExecuteSelect(DataSourceSelectArguments arguments) {
            if (SelectMethod.Length == 0) { 
                throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_SelectNotSupported, _owner.ID));
            } 
 
            if (CanSort) {
                arguments.AddSupportedCapabilities(DataSourceCapabilities.Sort); 
            }
            if (CanPage) {
                arguments.AddSupportedCapabilities(DataSourceCapabilities.Page);
            } 
            if (CanRetrieveTotalRowCount) {
                arguments.AddSupportedCapabilities(DataSourceCapabilities.RetrieveTotalRowCount); 
            } 
            arguments.RaiseUnsupportedCapabilitiesError(this);
 

            // Copy the parameters into a case insensitive dictionary
            IOrderedDictionary mergedParameters = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
            IDictionary selectParameters = SelectParameters.GetValues(_context, _owner); 
            foreach (DictionaryEntry de in selectParameters) {
                mergedParameters[de.Key] = de.Value; 
            } 

 
            // If caching is enabled, load DataView, DataSet, DataTable, or IEnumerable from cache
            bool cacheEnabled = _owner.Cache.Enabled;
            if (cacheEnabled) {
                object cachedData = _owner.LoadDataFromCache(arguments.StartRowIndex, arguments.MaximumRows); 
                if (cachedData != null) {
                    DataView dataView = cachedData as DataView; 
                    if (dataView != null) { 
                        if (arguments.RetrieveTotalRowCount && SelectCountMethod.Length == 0) {
                            arguments.TotalRowCount = dataView.Count; 
                        }
                        if (FilterExpression.Length > 0) {
                            // Since this type is not valid for filtering, throw if there is a filter
                            throw new NotSupportedException(SR.GetString(SR.ObjectDataSourceView_FilterNotSupported, _owner.ID)); 
                        }
                        if (String.IsNullOrEmpty(arguments.SortExpression)) { 
                            // If there is no sort expression, we can return the cached DataView 
                            // If sorting is requested, we don't use the cached one and we go create a new one (and we'll
                            // most likely get exception, since caching+sorting+DataView=exception). 
                            return dataView;
                        }

                        // Fall through as though the data wasn't in cache 
                    }
                    else { 
                        DataTable dataTable = FilteredDataSetHelper.GetDataTable(_owner, cachedData); 
                        if (dataTable != null) {
                            // If we got back a DataTable from cache, return that 
                            ProcessPagingData(arguments, mergedParameters);

                            return CreateFilteredDataView(dataTable, arguments.SortExpression, FilterExpression);
                        } 
                        else {
                            // If we got back an IEnumerable from cache, return that 
                            IEnumerable enumerableReturnValue = CreateEnumerableData(cachedData, arguments); 

                            ProcessPagingData(arguments, mergedParameters); 

                            return enumerableReturnValue;
                        }
                    } 
                }
            } 
 
            // We have to raise the Selecting event early on so that we respect
            // any changes the user has made to the DataSourceSelectArguments. 
            ObjectDataSourceSelectingEventArgs eventArgs = new ObjectDataSourceSelectingEventArgs(mergedParameters, arguments, false);
            OnSelecting(eventArgs);
            if (eventArgs.Cancel) {
                return null; 
            }
 
            // Create a copy of mergedParameters for queryRowCount that doesn't get all the Select, Sort, paging parameters 
            OrderedDictionary queryRowCountParameters = new OrderedDictionary(mergedParameters.Count);
            foreach (DictionaryEntry entry in mergedParameters) { 
                queryRowCountParameters.Add(entry.Key, entry.Value);
            }

            // NOTE: These special parameters are only added here so that they don't show up 
            // for the SelectCount operation.
 
            // Add the sort expression as a parameter if necessary 
            string sortParameterName = SortParameterName;
            if (sortParameterName.Length > 0) { 
                mergedParameters[sortParameterName] = arguments.SortExpression;

                // We reset the sort expression here so that we pretend as
                // though we're not really sorting (since the developer is 
                // worrying about it instead of us).
                arguments.SortExpression = String.Empty; 
            } 

 
            // Add the paging arguments as parameters if necessary
            if (EnablePaging) {
                string maximumRowsParameterName = MaximumRowsParameterName;
                string startRowIndexParameterName = StartRowIndexParameterName; 
                if (String.IsNullOrEmpty(maximumRowsParameterName) ||
                    String.IsNullOrEmpty(startRowIndexParameterName)) { 
                    throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_MissingPagingSettings, _owner.ID)); 
                }
                // Create a new dictionary with the paging information and merge it in (so we get type conversions) 
                IDictionary pagingParameters = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
                pagingParameters[maximumRowsParameterName] = arguments.MaximumRows;
                pagingParameters[startRowIndexParameterName] = arguments.StartRowIndex;
                MergeDictionaries(SelectParameters, pagingParameters, mergedParameters); 
            }
 
 
            Type type = GetType(TypeName);
            Debug.Assert(type != null, "Should not have a null type at this point"); 

            object instance = null;
            ObjectDataSourceResult result = null;
            try { 
                // Resolve and invoke the method
                ObjectDataSourceMethod method = GetResolvedMethodData(type, SelectMethod, mergedParameters, DataSourceOperation.Select); 
                result = InvokeMethod(method, false, ref instance); 

                // If the return value is null, there is no more processing to be done 
                if (result.ReturnValue == null) {
                    return null;
                }
 
                // Get the total row count if it is requested
                if (arguments.RetrieveTotalRowCount && SelectCountMethod.Length > 0) { 
                    int cachedTotalRowCount = -1; 
                    if (cacheEnabled) {
                        cachedTotalRowCount = _owner.LoadTotalRowCountFromCache(); 
                        if (cachedTotalRowCount >= 0) {
                            arguments.TotalRowCount = cachedTotalRowCount;
                        }
                    } 
                    if (cachedTotalRowCount < 0) {
                        cachedTotalRowCount = QueryTotalRowCount(queryRowCountParameters, arguments, true, ref instance); 
                        arguments.TotalRowCount = cachedTotalRowCount; 
                        if (cacheEnabled) {
                            _owner.SaveTotalRowCountToCache(cachedTotalRowCount); 
                        }
                    }
                }
            } 
            finally {
                if (instance != null) { 
                    ReleaseInstance(instance); 
                }
            } 

            // Process the return value
            // Order of precedence: DataView, DataTable, DataSet, IEnumerable, 
            { 
                // Check if the return value was a DataView
                DataView dataView = result.ReturnValue as DataView; 
                if (dataView != null) { 
                    if (arguments.RetrieveTotalRowCount && SelectCountMethod.Length == 0) {
                        arguments.TotalRowCount = dataView.Count; 
                    }
                    if (FilterExpression.Length > 0) {
                        // Since this type is not valid for filtering, throw if there is a filter
                        throw new NotSupportedException(SR.GetString(SR.ObjectDataSourceView_FilterNotSupported, _owner.ID)); 
                    }
 
                    if (!String.IsNullOrEmpty(arguments.SortExpression)) { 
                        if (cacheEnabled) {
                            // Since this type is not valid for caching, throw if caching is enabled 
                            throw new NotSupportedException(SR.GetString(SR.ObjectDataSourceView_CacheNotSupportedOnSortedDataView, _owner.ID));
                        }
                        dataView.Sort = arguments.SortExpression;
                    } 

                    // If caching is enabled, save data to cache 
                    if (cacheEnabled) { 
                        SaveDataAndRowCountToCache(arguments, result.ReturnValue);
                    } 
                    return dataView;
                }
                else {
                    // Check if the return value was a DataSet or DataTable 
                    DataTable dataTable = FilteredDataSetHelper.GetDataTable(_owner, result.ReturnValue);
                    if (dataTable != null) { 
                        if (arguments.RetrieveTotalRowCount && SelectCountMethod.Length == 0) { 
                            arguments.TotalRowCount = dataTable.Rows.Count;
                        } 

                        // If caching is enabled, save data to cache
                        if (cacheEnabled) {
                            SaveDataAndRowCountToCache(arguments, result.ReturnValue); 
                        }
                        // If we got a DataTable from the result, create a view with filtering and sorting 
                        return CreateFilteredDataView(dataTable, arguments.SortExpression, FilterExpression); 
                    }
                    else { 
                        // CreateEnumerableData will get an appropriate IEnumerable from the data, and also
                        // validate that filtering and sorting are not used.
                        IEnumerable enumerableReturnValue = CreateEnumerableData(result.ReturnValue, arguments);
 
                        // If caching is enabled, save data to cache
                        if (cacheEnabled) { 
                            if (enumerableReturnValue is IDataReader) { 
                                // IDataReader is specifically not supported with caching since the contract
                                // is that they are forward-only (i.e. not resettable). 
                                throw new NotSupportedException(SR.GetString(SR.ObjectDataSourceView_CacheNotSupportedOnIDataReader, _owner.ID));
                            }
                            SaveDataAndRowCountToCache(arguments, enumerableReturnValue);
                        } 
                        return enumerableReturnValue;
                    } 
                } 
            }
        } 

        /// 
        /// 
        protected override int ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) { 
            if (!CanUpdate) {
                throw new NotSupportedException(SR.GetString(SR.ObjectDataSourceView_UpdateNotSupported, _owner.ID)); 
            } 

            Type type = GetType(TypeName); 
            Debug.Assert(type != null, "Should not have a null type at this point");

            // Try to get the DataObject type. If we do get the type then we will construct
            // DataObjects representing the new (and possibly old) values. 
            Type dataObjectType = TryGetDataObjectType();
 
            ObjectDataSourceMethod method; 

            if (dataObjectType != null) { 
                if (ConflictDetection == ConflictOptions.CompareAllValues) {
                    // Build two DataObjects (Old + New)
                    if (oldValues == null) {
                        throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_Pessimistic, SR.GetString(SR.DataSourceView_update), _owner.ID, "oldValues")); 
                    }
 
                    IDictionary caseInsensitiveNewValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); 
                    IDictionary caseInsensitiveOldValues = null;
 
                    // We start out with the old values, just to pre-populate the list with items
                    // that might not have corresponding new values. For example if a GridView has
                    // a read-only field, there will be an old value, but no new value. The data object
                    // still has to have *some* value for a given field, so we just use the old value. 
                    MergeDictionaries(UpdateParameters, oldValues, caseInsensitiveNewValues);
                    MergeDictionaries(UpdateParameters, keys, caseInsensitiveNewValues); 
                    MergeDictionaries(UpdateParameters, values, caseInsensitiveNewValues); 

                    // For optimistic updates we require that there be old values, and then 
                    // we move them into a case-insensitive dictionary for merging.
                    if (oldValues == null) {
                        throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_Pessimistic, SR.GetString(SR.DataSourceView_update), _owner.ID, "oldValues"));
                    } 
                    caseInsensitiveOldValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
                    MergeDictionaries(UpdateParameters, oldValues, caseInsensitiveOldValues); 
                    MergeDictionaries(UpdateParameters, keys, caseInsensitiveOldValues); 

                    object newDataObject = BuildDataObject(dataObjectType, caseInsensitiveNewValues); 
                    object oldDataObject = BuildDataObject(dataObjectType, caseInsensitiveOldValues);

                    // Resolve and invoke the method
                    method = GetResolvedMethodData(type, UpdateMethod, dataObjectType, oldDataObject, newDataObject, DataSourceOperation.Update); 
                }
                else { 
                    // Build one DataObject (New) 

                    IDictionary caseInsensitiveNewValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); 

                    // We start out with the old values, just to pre-populate the list with items
                    // that might not have corresponding new values. For example if a GridView has
                    // a read-only field, there will be an old value, but no new value. The data object 
                    // still has to have *some* value for a given field, so we just use the old value.
                    MergeDictionaries(UpdateParameters, oldValues, caseInsensitiveNewValues); 
                    MergeDictionaries(UpdateParameters, keys, caseInsensitiveNewValues); 
                    MergeDictionaries(UpdateParameters, values, caseInsensitiveNewValues);
 
                    object newDataObject = BuildDataObject(dataObjectType, caseInsensitiveNewValues);

                    // Resolve and invoke the method
                    method = GetResolvedMethodData(type, UpdateMethod, dataObjectType, null, newDataObject, DataSourceOperation.Update); 
                }
 
                ObjectDataSourceMethodEventArgs eventArgs = new ObjectDataSourceMethodEventArgs(method.Parameters); 
                OnUpdating(eventArgs);
                if (eventArgs.Cancel) { 
                    return 0;
                }
            }
            else { 
                // Build parameter list that contains old values (optionally), new values, and keys
 
                IOrderedDictionary caseInsensitiveAllValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); 

                string oldValuesParameterFormatString = OldValuesParameterFormatString; 
                // Add UpdateParameters, but exclude params that are keys (they will be added later)
                IDictionary updateParams = UpdateParameters.GetValues(_context, _owner);
                if (keys != null) {
                    foreach (DictionaryEntry de in keys) { 
                        if (updateParams.Contains(de.Key)) {
                            updateParams.Remove(de.Key); 
                        } 
                    }
                } 
                MergeDictionaries(UpdateParameters, updateParams, caseInsensitiveAllValues);
                MergeDictionaries(UpdateParameters, values, caseInsensitiveAllValues);
                if (ConflictDetection == ConflictOptions.CompareAllValues) {
                    MergeDictionaries(UpdateParameters, oldValues, caseInsensitiveAllValues, oldValuesParameterFormatString); 
                }
                MergeDictionaries(UpdateParameters, keys, caseInsensitiveAllValues, oldValuesParameterFormatString); 
 
                ObjectDataSourceMethodEventArgs eventArgs = new ObjectDataSourceMethodEventArgs(caseInsensitiveAllValues);
                OnUpdating(eventArgs); 
                if (eventArgs.Cancel) {
                    return 0;
                }
 
                // Resolve and invoke the method
                method = GetResolvedMethodData(type, UpdateMethod, caseInsensitiveAllValues, DataSourceOperation.Update); 
            } 

            ObjectDataSourceResult result = InvokeMethod(method); 

            // Invalidate the cache and raise the change event to notify bound controls
            if (_owner.Cache.Enabled) {
                _owner.InvalidateCacheEntry(); 
            }
            OnDataSourceViewChanged(EventArgs.Empty); 
 
            return result.AffectedRows;
        } 

        /// 
        /// Returns true if the two parameters represent the same type of operation.
        ///  
        private static DataObjectMethodType GetMethodTypeFromOperation(DataSourceOperation operation) {
            switch (operation) { 
                case DataSourceOperation.Delete: 
                    return DataObjectMethodType.Delete;
                case DataSourceOperation.Insert: 
                    return DataObjectMethodType.Insert;
                case DataSourceOperation.Select:
                    return DataObjectMethodType.Select;
                case DataSourceOperation.Update: 
                    return DataObjectMethodType.Update;
            } 
            throw new ArgumentOutOfRangeException("operation"); 
        }
 
        /// 
        /// Extracts the values of all output (out and ref) parameters given a list of parameters and their respective values.
        /// 
        private IDictionary GetOutputParameters(ParameterInfo[] parameters, object[] values) { 
            IDictionary outputParameters = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
            for (int i = 0; i < parameters.Length; i++) { 
                ParameterInfo parameter = parameters[i]; 
                if (parameter.ParameterType.IsByRef) {
                    outputParameters[parameter.Name] = values[i]; 
                }
            }
            return outputParameters;
        } 

        private ObjectDataSourceMethod GetResolvedMethodData(Type type, string methodName, Type dataObjectType, object oldDataObject, object newDataObject, DataSourceOperation operation) { 
            Debug.Assert(dataObjectType != null, "This overload of GetResolvedMethodData should only be called when using a DataObject"); 
            Debug.Assert(oldDataObject != null || newDataObject != null, "Did not expect both oldDataObject and newDataObject to be null");
 
            // Get a list of all the overloads of the requested method
            MethodInfo[] methods = type.GetMethods(
                BindingFlags.Public |
                BindingFlags.Instance | 
                BindingFlags.Static |
                BindingFlags.FlattenHierarchy); 
 
            MethodInfo matchedMethod = null;
            ParameterInfo[] matchedMethodParameters = null; 


            int requiredParameterCount;
            if (oldDataObject == null) { 
                requiredParameterCount = 1;
            } 
            else { 
                if (newDataObject == null) {
                    requiredParameterCount = 1; 
                }
                else {
                    requiredParameterCount = 2;
                } 
            }
 
 
            foreach (MethodInfo mi in methods) {
                if (String.Equals(methodName, mi.Name, StringComparison.OrdinalIgnoreCase)) { 
                    if (mi.IsGenericMethodDefinition) {
                        // We do not support binding to generic methods, e.g. public void DoSomething(T t)
                        continue;
                    } 

                    ParameterInfo[] methodParameters = mi.GetParameters(); 
 
                    int methodParametersCount = methodParameters.Length;
 
                    if (methodParametersCount == requiredParameterCount) {
                        if (requiredParameterCount == 1 &&
                            methodParameters[0].ParameterType == dataObjectType) {
                            // Only one parameter, of proper type 
                            // This is only valid for insert, delete, and non-optimistic update
                            matchedMethod = mi; 
                            matchedMethodParameters = methodParameters; 
                            break;
                        } 
                        if (requiredParameterCount == 2 &&
                            methodParameters[0].ParameterType == dataObjectType &&
                            methodParameters[1].ParameterType == dataObjectType) {
                            // Two parameters of proper type in Update 
                            // This is only valid for optimistic update
                            matchedMethod = mi; 
                            matchedMethodParameters = methodParameters; 
                            break;
                        } 
                    }
                }
            }
 
            if (matchedMethod == null) {
                throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_MethodNotFoundForDataObject, _owner.ID, methodName, dataObjectType.FullName)); 
            } 

            Debug.Assert(matchedMethodParameters != null, "Method parameters should not be null if a method was found"); 

            // Set up parameter array for method call
            OrderedDictionary parameters = new OrderedDictionary(2, StringComparer.OrdinalIgnoreCase);
 
            if (oldDataObject == null) {
                parameters.Add(matchedMethodParameters[0].Name, newDataObject); 
            } 
            else {
                if (newDataObject == null) { 
                    parameters.Add(matchedMethodParameters[0].Name, oldDataObject);
                }
                else {
                    // We know that we matched on 2 objects for a optimistic update. 
                    // Match the parameters based on the format string so we know which one is the old
                    // object and which is the new, then pass objects into the method in the correct order. 
                    string param0Name = matchedMethodParameters[0].Name; 
                    string param1Name = matchedMethodParameters[1].Name;
                    string formattedParamName = String.Format(CultureInfo.InvariantCulture, OldValuesParameterFormatString, param0Name); 
                    if (String.Equals(param1Name, formattedParamName, StringComparison.OrdinalIgnoreCase)) {
                        parameters.Add(param0Name, newDataObject);
                        parameters.Add(param1Name, oldDataObject);
                    } 
                    else {
                        formattedParamName = String.Format(CultureInfo.InvariantCulture, OldValuesParameterFormatString, param1Name); 
                        if (String.Equals(param0Name, formattedParamName, StringComparison.OrdinalIgnoreCase)) { 
                            parameters.Add(param0Name, oldDataObject);
                            parameters.Add(param1Name, newDataObject); 
                        }
                        else {
                            throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_NoOldValuesParams, _owner.ID));
                        } 
                    }
                } 
            } 

            // The parameters collection is always readonly in this case since we 
            // do not want the user adding/removing the known objects.
            return new ObjectDataSourceMethod(operation, type, matchedMethod, parameters.AsReadOnly());
        }
 
        /// 
        /// Resolves a method based on a type and the name of the method. Overload resolution is 
        /// performed primarily based on the names of parameters passed in the two dictionary 
        /// parameters. Conflict resolution is done based on a rating scale of confidence levels
        /// (see comments in this method). 
        /// The return value is the MethodInfo that was found along with an array of parameter
        /// values to be passed in for the invocation.
        /// 
        private ObjectDataSourceMethod GetResolvedMethodData(Type type, string methodName, IDictionary allParameters, DataSourceOperation operation) { 
            Debug.Assert(allParameters != null, "The 'allParameters' dictionary should never be null");
 
            // Since there is no method type for SelectCount, we special case it 
            bool isSelectCount = (operation == DataSourceOperation.SelectCount);
            DataObjectMethodType methodType = DataObjectMethodType.Select; 
            if (!isSelectCount) {
                methodType = GetMethodTypeFromOperation(operation);
            }
 
            // Get a list of all the overloads of the requested method
            MethodInfo[] methods = type.GetMethods( 
                BindingFlags.Public | 
                BindingFlags.Instance |
                BindingFlags.Static | 
                BindingFlags.FlattenHierarchy);
            MethodInfo matchedMethod = null;
            ParameterInfo[] matchedMethodParameters = null;
 
            // Indicates how confident we are that a method overload is a good match
            // -1 - indicates no confidence - no appropriate methods have been found at all 
            // 0 - indicates low confidence - only parameter names match 
            // 1 - indicates medium confidence - parameter names match, method is DataObjectMethod
            // 2 - indicates high confidence - parameter names match, method is DataObjectMethod, is default method 
            int highestConfidence = -1;
            bool confidenceConflict = false; // Indicates that there is more than one method at the current highest confidence level

            int allParameterCount = allParameters.Count; 

            foreach (MethodInfo mi in methods) { 
                if (String.Equals(methodName, mi.Name, StringComparison.OrdinalIgnoreCase)) { 
                    if (mi.IsGenericMethodDefinition) {
                        // We do not support binding to generic methods, e.g. public void DoSomething(T t) 
                        continue;
                    }

                    ParameterInfo[] methodParameters = mi.GetParameters(); 

                    int methodParametersCount = methodParameters.Length; 
 
                    // We are not using DataObject. There is either a Select operation, or it is an
                    // Update/Insert/Delete operation that does not use DataObjects. 

                    // First check if the parameter counts match
                    if (methodParametersCount != allParameterCount) {
                        continue; 
                    }
 
                    // Check if all the parameter names match 
                    bool parameterMismatch = false;
                    foreach (ParameterInfo pi in methodParameters) { 
                        if (!allParameters.Contains(pi.Name)) {
                            parameterMismatch = true;
                            break;
                        } 
                    }
                    if (parameterMismatch) { 
                        continue; 
                    }
 
                    int confidence = 0; // See comment above regarding confidence

                    if (!isSelectCount) {
                        DataObjectMethodAttribute attr = Attribute.GetCustomAttribute(mi, typeof(DataObjectMethodAttribute), true) as DataObjectMethodAttribute; 
                        if (attr != null) {
                            if (attr.MethodType == methodType) { 
                                if (attr.IsDefault) { 
                                    // Method is decorated and is default
                                    confidence = 2; 
                                }
                                else {
                                    // Method is decorated but not default
                                    confidence = 1; 
                                }
                            } 
                        } 
                    }
 
                    // If we found another method
                    if (confidence == highestConfidence) {
                        confidenceConflict = true;
                    } 
                    else {
                        // If method looks like it's the best match so far, store it 
                        if (confidence > highestConfidence) { 
                            highestConfidence = confidence;
                            confidenceConflict = false; 
                            matchedMethod = mi;
                            matchedMethodParameters = methodParameters;
                        }
                    } 
                }
            } 
 
            if (confidenceConflict) {
                // There was more than one method that looked like a good match, but none had 
                // a higher confidence level than the others, so we fail. See comment above
                // regarding confidence levels.
                throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_MultipleOverloads, _owner.ID));
            } 

            if (matchedMethod == null) { 
                if (allParameterCount == 0) { 
                    throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_MethodNotFoundNoParams, _owner.ID, methodName));
                } 
                else {
                    string[] paramNames = new string[allParameterCount];
                    allParameters.Keys.CopyTo(paramNames, 0);
                    string paramString = String.Join(", ", paramNames); 
                    throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_MethodNotFoundWithParams, _owner.ID, methodName, paramString));
                } 
            } 

            Debug.Assert(matchedMethodParameters != null, "Method parameters should not be null if a method was found"); 

            OrderedDictionary parameters = null;

            // Create the actual parameter list to be passed to the method 
            int methodParameterCount = matchedMethodParameters.Length;
            if (methodParameterCount > 0) { 
                parameters = new OrderedDictionary(methodParameterCount, StringComparer.OrdinalIgnoreCase); 
                bool convertNullToDBNull = ConvertNullToDBNull;
                for (int i = 0; i < matchedMethodParameters.Length; i++) { 
                    ParameterInfo methodParameter = matchedMethodParameters[i];
                    string paramName = methodParameter.Name;
                    // Check if the required parameter exists in the input parameters
                    Debug.Assert(allParameters.Contains(paramName)); 

                    object parameterValue = allParameters[paramName]; 
                    if (convertNullToDBNull && (parameterValue == null)) { 
                        parameterValue = DBNull.Value;
                    } 
                    else {
                        parameterValue = BuildObjectValue(parameterValue, methodParameter.ParameterType, paramName);
                    }
 
                    parameters.Add(paramName, parameterValue);
                } 
            } 

            return new ObjectDataSourceMethod(operation, type, matchedMethod, parameters); 
        }

        private Type GetType(string typeName) {
            if (TypeName.Length == 0) { 
                throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_TypeNotSpecified, _owner.ID));
            } 
 
            // Load the type using BuildManager (do not throw on fail, ignore case)
            Type type = BuildManager.GetType(TypeName, false, true); 

            // If the type was not found, throw
            if (type == null) {
                throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_TypeNotFound, _owner.ID)); 
            }
 
            return type; 
        }
 
        public int Insert(IDictionary values) {
            return ExecuteInsert(values);
        }
 
        private ObjectDataSourceResult InvokeMethod(ObjectDataSourceMethod method) {
            object instance = null; 
            return InvokeMethod(method, true, ref instance); 
        }
 
        /// 
        /// Invokes a given method with the specified parameters. This will also raise
        /// the appropriate post event after execution.
        ///  
        private ObjectDataSourceResult InvokeMethod(ObjectDataSourceMethod method, bool disposeInstance, ref object instance) {
            // If the method is not static, we need to create an instance of the type 
 
            if (method.MethodInfo.IsStatic) {
                if (instance != null) { 
                    ReleaseInstance(instance);
                }
                instance = null;
            } 
            else {
                if (instance == null) { 
                    // Raise event to allow page developer to supply a custom instance of the type 
                    ObjectDataSourceEventArgs objectEventArgs = new ObjectDataSourceEventArgs(null);
                    OnObjectCreating(objectEventArgs); 

                    // If page developer did not create a custom instance, we attempt to instantiate
                    // the object ourselves, and raise the ObjectCreated event
                    if (objectEventArgs.ObjectInstance == null) { 
                        objectEventArgs.ObjectInstance = Activator.CreateInstance(method.Type);
 
                        // Raise ObjectCreated event with the same event args 
                        OnObjectCreated(objectEventArgs);
                    } 
                    instance = objectEventArgs.ObjectInstance;
                }
            }
 

            // Call the method and if an exception is thrown, hold on to it to let the page developer attempt to handle it 
            object returnValue = null; 
            int affectedRows = -1;
 
            bool eventFired = false;
            object[] parameterValues = null;
            if (method.Parameters != null && method.Parameters.Count > 0) {
                parameterValues = new object[method.Parameters.Count]; 
                for (int i = 0; i < method.Parameters.Count; i++) {
                    parameterValues[i] = method.Parameters[i]; 
                } 
            }
            try { 
                returnValue = method.MethodInfo.Invoke(instance, parameterValues);
            }
            catch (Exception ex) {
                // Collect output parameters 
                IDictionary outputParameters = GetOutputParameters(method.MethodInfo.GetParameters(), parameterValues);
                ObjectDataSourceStatusEventArgs statusEventArgs = new ObjectDataSourceStatusEventArgs(returnValue, outputParameters, ex); 
                eventFired = true; 
                switch (method.Operation) {
                    case DataSourceOperation.Delete: 
                        OnDeleted(statusEventArgs);
                        break;
                    case DataSourceOperation.Insert:
                        OnInserted(statusEventArgs); 
                        break;
                    case DataSourceOperation.Select: 
                        OnSelected(statusEventArgs); 
                        break;
                    case DataSourceOperation.SelectCount: 
                        OnSelected(statusEventArgs);
                        break;
                    case DataSourceOperation.Update:
                        OnUpdated(statusEventArgs); 
                        break;
                } 
                affectedRows = statusEventArgs.AffectedRows; 

                if (!statusEventArgs.ExceptionHandled) { 
                    throw;
                }
            }
            finally { 
                // This block is to ensure that we always at least try to raise
                // the Disposing event, even if the other event handlers threw 
                // exceptions. 
                try {
                    if (eventFired == false) { 
                        // Collect output parameters
                        IDictionary outputParameters = GetOutputParameters(method.MethodInfo.GetParameters(), parameterValues);
                        ObjectDataSourceStatusEventArgs statusEventArgs = new ObjectDataSourceStatusEventArgs(returnValue, outputParameters);
                        switch (method.Operation) { 
                            case DataSourceOperation.Delete:
                                OnDeleted(statusEventArgs); 
                                break; 
                            case DataSourceOperation.Insert:
                                OnInserted(statusEventArgs); 
                                break;
                            case DataSourceOperation.Select:
                                OnSelected(statusEventArgs);
                                break; 
                            case DataSourceOperation.SelectCount:
                                OnSelected(statusEventArgs); 
                                break; 
                            case DataSourceOperation.Update:
                                OnUpdated(statusEventArgs); 
                                break;
                        }
                        affectedRows = statusEventArgs.AffectedRows;
                    } 
                }
                finally { 
                    // Raise ObjectDisposing event 
                    if (instance != null && disposeInstance) {
                        ReleaseInstance(instance); 
                        instance = null;
                    }
                }
            } 

            return new ObjectDataSourceResult(returnValue, affectedRows); 
        } 

        ///  
        /// Loads view state.
        /// 
        protected virtual void LoadViewState(object savedState) {
            if (savedState == null) 
                return;
 
            Pair myState = (Pair)savedState; 

            if (myState.First != null) 
                ((IStateManager)SelectParameters).LoadViewState(myState.First);

            if (myState.Second != null)
                ((IStateManager)FilterParameters).LoadViewState(myState.Second); 
        }
 
        private static void MergeDictionaries(ParameterCollection reference, IDictionary source, IDictionary destination) { 
            MergeDictionaries(reference, source, destination, null);
        } 

        /// 
        /// Merges new values in the source dictionary with old values in the destination dictionary.
        /// The reference parameter is used to assign types to values that got merged. 
        /// If a format string is specified, it will be applied to the parameter name when it is
        /// added to the destination dictionary. 
        ///  
        private static void MergeDictionaries(ParameterCollection reference, IDictionary source, IDictionary destination, string parameterNameFormatString) {
            Debug.Assert(destination != null); 
            Debug.Assert(reference != null);

            if (source != null) {
                foreach (DictionaryEntry de in source) { 
                    object value = de.Value;
                    // If the reference collection contains this parameter, we will convert its type to match it 
                    Parameter referenceParameter = null; 
                    string parameterName = (string)de.Key;
                    if (parameterNameFormatString != null) { 
                        parameterName = String.Format(CultureInfo.InvariantCulture, parameterNameFormatString, parameterName);
                    }
                    foreach (Parameter p in reference) {
                        if (String.Equals(p.Name, parameterName, StringComparison.OrdinalIgnoreCase)) { 
                            referenceParameter = p;
                            break; 
                        } 
                    }
                    if (referenceParameter != null) { 
                        value = Parameter.GetValue(value, referenceParameter.DefaultValue, referenceParameter.Type, referenceParameter.ConvertEmptyStringToNull, true);
                    }
                    destination[parameterName] = value;
                } 
            }
        } 
 
        /// 
        /// Raises the Deleted event. 
        /// 
        protected virtual void OnDeleted(ObjectDataSourceStatusEventArgs e) {
            ObjectDataSourceStatusEventHandler handler = Events[EventDeleted] as ObjectDataSourceStatusEventHandler;
            if (handler != null) { 
                handler(this, e);
            } 
        } 

        ///  
        /// Raises the Deleting event.
        /// 
        protected virtual void OnDeleting(ObjectDataSourceMethodEventArgs e) {
            ObjectDataSourceMethodEventHandler handler = Events[EventDeleting] as ObjectDataSourceMethodEventHandler; 
            if (handler != null) {
                handler(this, e); 
            } 
        }
 
        protected virtual void OnFiltering(ObjectDataSourceFilteringEventArgs e) {
            ObjectDataSourceFilteringEventHandler handler = Events[EventFiltering] as ObjectDataSourceFilteringEventHandler;
            if (handler != null) {
                handler(this, e); 
            }
        } 
 
        /// 
        /// Raises the Inserted event. 
        /// 
        protected virtual void OnInserted(ObjectDataSourceStatusEventArgs e) {
            ObjectDataSourceStatusEventHandler handler = Events[EventInserted] as ObjectDataSourceStatusEventHandler;
            if (handler != null) { 
                handler(this, e);
            } 
        } 

        ///  
        /// Raises the Inserting event.
        /// 
        protected virtual void OnInserting(ObjectDataSourceMethodEventArgs e) {
            ObjectDataSourceMethodEventHandler handler = Events[EventInserting] as ObjectDataSourceMethodEventHandler; 
            if (handler != null) {
                handler(this, e); 
            } 
        }
 
        /// 
        /// Raises the ObjectCreated event.
        /// 
        protected virtual void OnObjectCreated(ObjectDataSourceEventArgs e) { 
            ObjectDataSourceObjectEventHandler handler = Events[EventObjectCreated] as ObjectDataSourceObjectEventHandler;
            if (handler != null) { 
                handler(this, e); 
            }
        } 

        /// 
        /// Raises the ObjectCreating event.
        ///  
        protected virtual void OnObjectCreating(ObjectDataSourceEventArgs e) {
            ObjectDataSourceObjectEventHandler handler = Events[EventObjectCreating] as ObjectDataSourceObjectEventHandler; 
            if (handler != null) { 
                handler(this, e);
            } 
        }

        /// 
        /// Raises the ObjectDisposing event. 
        /// 
        protected virtual void OnObjectDisposing(ObjectDataSourceDisposingEventArgs e) { 
            ObjectDataSourceDisposingEventHandler handler = Events[EventObjectDisposing] as ObjectDataSourceDisposingEventHandler; 
            if (handler != null) {
                handler(this, e); 
            }
        }

        ///  
        /// Raises the Selected event.
        ///  
        protected virtual void OnSelected(ObjectDataSourceStatusEventArgs e) { 
            ObjectDataSourceStatusEventHandler handler = Events[EventSelected] as ObjectDataSourceStatusEventHandler;
            if (handler != null) { 
                handler(this, e);
            }
        }
 
        /// 
        /// Raises the Selecting event. 
        ///  
        protected virtual void OnSelecting(ObjectDataSourceSelectingEventArgs e) {
            ObjectDataSourceSelectingEventHandler handler = Events[EventSelecting] as ObjectDataSourceSelectingEventHandler; 
            if (handler != null) {
                handler(this, e);
            }
        } 

        ///  
        /// Raises the Updated event. 
        /// 
        protected virtual void OnUpdated(ObjectDataSourceStatusEventArgs e) { 
            ObjectDataSourceStatusEventHandler handler = Events[EventUpdated] as ObjectDataSourceStatusEventHandler;
            if (handler != null) {
                handler(this, e);
            } 
        }
 
        ///  
        /// Raises the Updating event.
        ///  
        protected virtual void OnUpdating(ObjectDataSourceMethodEventArgs e) {
            ObjectDataSourceMethodEventHandler handler = Events[EventUpdating] as ObjectDataSourceMethodEventHandler;
            if (handler != null) {
                handler(this, e); 
            }
        } 
 
        /// 
        /// Populates the paging information in the DataSourceSelectArguments and 
        /// saves the data to cache if necessary.
        /// 
        private void ProcessPagingData(DataSourceSelectArguments arguments, IOrderedDictionary parameters) {
            if (arguments.RetrieveTotalRowCount) { 
                int cachedTotalRowCount = _owner.LoadTotalRowCountFromCache();
                if (cachedTotalRowCount >= 0) { 
                    arguments.TotalRowCount = cachedTotalRowCount; 
                }
                else { 
                    // query for row count and then save it in cache
                    object dummyInstance = null;
                    cachedTotalRowCount = QueryTotalRowCount(parameters, arguments, true, ref dummyInstance);
                    arguments.TotalRowCount = cachedTotalRowCount; 
                    _owner.SaveTotalRowCountToCache(cachedTotalRowCount);
                } 
            } 
        }
 
        /// 
        /// Executes the SelectCountMethod to retrieve the total row count.
        /// 
        private int QueryTotalRowCount(IOrderedDictionary mergedParameters, DataSourceSelectArguments arguments, bool disposeInstance, ref object instance) { 
            if (SelectCountMethod.Length > 0) {
                ObjectDataSourceSelectingEventArgs eventArgs = new ObjectDataSourceSelectingEventArgs(mergedParameters, arguments, true); 
                OnSelecting(eventArgs); 
                if (eventArgs.Cancel) {
                    return -1; 
                }

                Type type = GetType(TypeName);
                Debug.Assert(type != null, "Should not have a null type at this point"); 

                ObjectDataSourceMethod method = GetResolvedMethodData(type, SelectCountMethod, mergedParameters, DataSourceOperation.SelectCount); 
                ObjectDataSourceResult result = InvokeMethod(method, disposeInstance, ref instance); 
                if (result.ReturnValue != null && result.ReturnValue is int) {
                    return (int)result.ReturnValue; 
                }
            }

            // Unknown total row count 
            return -1;
        } 
 
        private void ReleaseInstance(object instance) {
            Debug.Assert(instance != null, "ReleaseInstance: Instance shouldn't be null"); 
            ObjectDataSourceDisposingEventArgs disposingEventArgs = new ObjectDataSourceDisposingEventArgs(instance);
            OnObjectDisposing(disposingEventArgs);

            // Only call IDisposable.Dispose() if the page developer did not cancel 
            if (!disposingEventArgs.Cancel) {
                // If the object implement IDisposable, call Dispose() 
                IDisposable disposableObject = instance as IDisposable; 
                if (disposableObject != null) {
                    disposableObject.Dispose(); 
                }
            }
        }
 
        private void SaveDataAndRowCountToCache(DataSourceSelectArguments arguments, object data) {
            // Make sure total row count is saved first, since this is the parent key. 
            // If it's saved after the data, saving the total row count will invalidate 
            // the data cache.
            if (arguments.RetrieveTotalRowCount) { 
                int totalRowCount = _owner.LoadTotalRowCountFromCache();
                if (totalRowCount != arguments.TotalRowCount) {
                    _owner.SaveTotalRowCountToCache(arguments.TotalRowCount);
                } 
            }
            _owner.SaveDataToCache(arguments.StartRowIndex, arguments.MaximumRows, data); 
        } 

        ///  
        /// Saves view state.
        /// 
        protected virtual object SaveViewState() {
            Pair myState = new Pair(); 

            myState.First = (_selectParameters != null) ? ((IStateManager)_selectParameters).SaveViewState() : null; 
            myState.Second = (_filterParameters != null) ? ((IStateManager)_filterParameters).SaveViewState() : null; 

            if ((myState.First == null) && 
                (myState.Second == null)) {
                return null;
            }
            return myState; 
        }
 
        public IEnumerable Select(DataSourceSelectArguments arguments) { 
            return ExecuteSelect(arguments);
        } 

        /// 
        /// Event handler for SelectParametersChanged event.
        ///  
        private void SelectParametersChangedEventHandler(object o, EventArgs e) {
            OnDataSourceViewChanged(EventArgs.Empty); 
        } 

 
        /// 
        /// Starts tracking view state.
        /// 
        protected virtual void TrackViewState() { 
            _tracking = true;
 
            if (_selectParameters != null) { 
                ((IStateManager)_selectParameters).TrackViewState();
            } 
            if (_filterParameters != null) {
                ((IStateManager)_filterParameters).TrackViewState();
            }
        } 

        private Type TryGetDataObjectType() { 
            // Load the data object type using BuildManager (do not throw on fail, ignore case) 
            // We only care about it for Update/Insert/Delete operations since it's not supported for Select
            string dataObjectTypeName = DataObjectTypeName; 
            if (dataObjectTypeName.Length == 0) {
                return null;
            }
            Type dataObjectType = BuildManager.GetType(dataObjectTypeName, false, true); 
            if (dataObjectType == null) {
                // If the type was not found, throw 
                throw new InvalidOperationException(SR.GetString(SR.ObjectDataSourceView_DataObjectTypeNotFound, _owner.ID)); 
            }
            return dataObjectType; 
        }

        public int Update(IDictionary keys, IDictionary values, IDictionary oldValues) {
            return ExecuteUpdate(keys, values, oldValues); 
        }
 
        #region IStateManager implementation 
        /// 
        bool IStateManager.IsTrackingViewState { 
            get {
                return IsTrackingViewState;
            }
        } 

        ///  
        void IStateManager.LoadViewState(object savedState) { 
            LoadViewState(savedState);
        } 


        /// 
        object IStateManager.SaveViewState() { 
            return SaveViewState();
        } 
 

        ///  
        void IStateManager.TrackViewState() {
            TrackViewState();
        }
        #endregion 

 
        private struct ObjectDataSourceMethod { 
            internal DataSourceOperation Operation;
            internal Type Type; 
            internal OrderedDictionary Parameters;
            internal MethodInfo MethodInfo;

            internal ObjectDataSourceMethod(DataSourceOperation operation, Type type, MethodInfo methodInfo, OrderedDictionary parameters) { 
                Operation = operation;
                Type = type; 
                Parameters = parameters; 
                MethodInfo = methodInfo;
            } 
        }

        private class ObjectDataSourceResult {
            internal object ReturnValue; 
            internal int AffectedRows;
 
            internal ObjectDataSourceResult(object returnValue, int affectedRows) { 
                ReturnValue = returnValue;
                AffectedRows = affectedRows; 
            }
        }
    }
} 



                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK