ObjectDataSourceView.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / UI / WebControls / ObjectDataSourceView.cs / 1305376 / 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.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. 
    /// 
    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 = referenceParameter.GetValue(value, 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; 
            } 
        }
    } 
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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