/// <summary> /// Invokes the Update method and gets the result. /// </summary> protected virtual object GetUpdateMethodResult(IDictionary keys, IDictionary values, IDictionary oldValues) { ModelDataSourceMethod method = EvaluateUpdateMethodParameters(keys, values, oldValues); ModelDataMethodResult result = InvokeMethod(method); return(result.ReturnValue); }
/// <summary> /// Invokes the Insert method and gets the result. /// </summary> protected virtual object GetInsertMethodResult(IDictionary values) { ModelDataSourceMethod method = EvaluateInsertMethodParameters(values); ModelDataMethodResult result = InvokeMethod(method); return(result.ReturnValue); }
//Evaluates the select method parameters using the custom value provides. This is done after page load so that //we raise the DataSourceChanged event if the values of parameters change. private void EvaluateSelectParameters() { if (!String.IsNullOrEmpty(SelectMethod)) { ModelDataSourceMethod method = FindMethod(SelectMethod); EvaluateMethodParameters(DataSourceOperation.Select, method, controlValues: null, isPageLoadComplete: true); } }
/// <summary> /// Invokes the select method and gets the result. Also handles auto paging and sorting when required. /// </summary> /// <param name="arguments">The DataSourceSelectArguments for the select operation. /// When applicable, this method sets the TotalRowCount out parameter in the arguments. /// </param> /// <returns>The return value from the select method.</returns> protected virtual object GetSelectMethodResult(DataSourceSelectArguments arguments) { if (SelectMethod.Length == 0) { throw new InvalidOperationException(SR.GetString(SR.ModelDataSourceView_SelectNotSupported)); } DataSourceSelectResultProcessingOptions options = null; ModelDataSourceMethod method = EvaluateSelectMethodParameters(arguments, out options); ModelDataMethodResult result = InvokeMethod(method); return(ProcessSelectMethodResult(arguments, options, result)); }
protected virtual ModelDataSourceMethod EvaluateInsertMethodParameters(IDictionary values) { if (!CanInsert) { throw new NotSupportedException(SR.GetString(SR.ModelDataSourceView_InsertNotSupported)); } IDictionary caseInsensitiveNewValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); MergeDictionaries(values, caseInsensitiveNewValues); ModelDataSourceMethod method = FindMethod(InsertMethod); EvaluateMethodParameters(DataSourceOperation.Insert, method, caseInsensitiveNewValues); return(method); }
protected virtual ModelDataSourceMethod EvaluateDeleteMethodParameters(IDictionary keys, IDictionary oldValues) { if (!CanDelete) { throw new NotSupportedException(SR.GetString(SR.ModelDataSourceView_DeleteNotSupported)); } IDictionary caseInsensitiveOldValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); MergeDictionaries(keys, caseInsensitiveOldValues); MergeDictionaries(oldValues, caseInsensitiveOldValues); ModelDataSourceMethod method = FindMethod(DeleteMethod); EvaluateMethodParameters(DataSourceOperation.Delete, method, caseInsensitiveOldValues); return(method); }
protected virtual ModelDataSourceMethod EvaluateUpdateMethodParameters(IDictionary keys, IDictionary values, IDictionary oldValues) { if (!CanUpdate) { throw new NotSupportedException(SR.GetString(SR.ModelDataSourceView_UpdateNotSupported)); } 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(oldValues, caseInsensitiveNewValues); MergeDictionaries(keys, caseInsensitiveNewValues); MergeDictionaries(values, caseInsensitiveNewValues); ModelDataSourceMethod method = FindMethod(UpdateMethod); EvaluateMethodParameters(DataSourceOperation.Update, method, caseInsensitiveNewValues); return(method); }
/// <summary> /// Invokes the data method in a secure fashion. /// </summary> /// <param name="method"> /// The ModelDataSouceMethod object specifying the Instance on which the method should be invoked (null for static methods), /// the MethodInfo of the method to be invoked and the Parameters for invoking the method. /// All the above properties should be populated before this method is called. /// </param> /// <returns> /// A ModelDataSouceResult object containing the ReturnValue of the method and any out parameters. /// </returns> protected virtual ModelDataMethodResult InvokeMethod(ModelDataSourceMethod method) { object returnValue = null; 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]; } } returnValue = _methodInvokerDispatcher(method.MethodInfo, method.Instance, parameterValues); OrderedDictionary outputParameters = GetOutputParameters(method.MethodInfo.GetParameters(), parameterValues); method.Instance = null; //Data Method is done executing, turn off the TryUpdateModel _owner.DataControl.Page.SetActiveValueProvider(null); return(new ModelDataMethodResult(returnValue, outputParameters)); }
private object GetUpdateMethodResult(IDictionary keys, IDictionary values, IDictionary oldValues, ModelDataSourceMethod method, bool isAsyncMethod, CancellationToken? cancellationToken) { method = method == null ? EvaluateUpdateMethodParameters(keys, values, oldValues) : EvaluateUpdateMethodParameters(keys, values, oldValues, method); SetCancellationTokenIfRequired(method, isAsyncMethod, cancellationToken); ModelDataMethodResult result = InvokeMethod(method, isAsyncMethod); return result.ReturnValue; }
private ModelDataSourceMethod EvaluateDeleteMethodParameters(IDictionary keys, IDictionary oldValues, ModelDataSourceMethod method) { if (!CanDelete) { throw new NotSupportedException(SR.GetString(SR.ModelDataSourceView_DeleteNotSupported)); } IDictionary caseInsensitiveOldValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); MergeDictionaries(keys, caseInsensitiveOldValues); MergeDictionaries(oldValues, caseInsensitiveOldValues); method = method ?? FindMethod(DeleteMethod); EvaluateMethodParameters(DataSourceOperation.Delete, method, caseInsensitiveOldValues); return method; }
private ModelDataSourceMethod EvaluateInsertMethodParameters(IDictionary values, ModelDataSourceMethod method) { if (!CanInsert) { throw new NotSupportedException(SR.GetString(SR.ModelDataSourceView_InsertNotSupported)); } IDictionary caseInsensitiveNewValues = new OrderedDictionary(StringComparer.OrdinalIgnoreCase); MergeDictionaries(values, caseInsensitiveNewValues); method = method ?? FindMethod(InsertMethod); EvaluateMethodParameters(DataSourceOperation.Insert, method, caseInsensitiveNewValues); return method; }
private ModelDataSourceMethod EvaluateSelectMethodParameters(DataSourceSelectArguments arguments, ModelDataSourceMethod method, bool isAsyncSelect, out DataSourceSelectResultProcessingOptions selectResultProcessingOptions) { IOrderedDictionary mergedParameters = MergeSelectParameters(arguments); // Resolve the method method = method ?? FindMethod(SelectMethod); Type selectMethodReturnType = method.MethodInfo.ReturnType; if (isAsyncSelect) { selectMethodReturnType = ExtractAsyncSelectReturnType(selectMethodReturnType); } Type modelType = ModelType; if (modelType == null) { //When ModelType is not specified but SelectMethod returns IQueryable<T>, we treat T as model type for auto paging and sorting. //If the return type is something like CustomType<U,T> : IQueryable<T>, we should use T for paging and sorting, hence //we walk over the return type's generic arguments for a proper match. foreach (Type typeParameter in selectMethodReturnType.GetGenericArguments()) { if (typeof(IQueryable<>).MakeGenericType(typeParameter).IsAssignableFrom(selectMethodReturnType)) { modelType = typeParameter; } } } Type queryableModelType = (modelType != null) ? typeof(IQueryable<>).MakeGenericType(modelType) : null; //We do auto paging or auto sorting when the select method is returning an IQueryable and does not have parameters for paging or sorting. bool isReturningQueryable = queryableModelType != null && queryableModelType.IsAssignableFrom(selectMethodReturnType); if (isAsyncSelect && isReturningQueryable) { // async select method does not support returning IQueryable<>. throw new InvalidOperationException(SR.GetString(SR.ModelDataSourceView_InvalidAsyncSelectReturnType, modelType)); } bool autoPage = false; bool autoSort = false; if (arguments.StartRowIndex >= 0 && arguments.MaximumRows > 0) { autoPage = IsAutoPagingRequired(method.MethodInfo, isReturningQueryable, isAsyncSelect); if (isAsyncSelect) { Debug.Assert(!autoPage, "auto-paging should not be true when using async select method"); // custom paging is not supported if the return type is not SelectResult if (typeof(SelectResult) != selectMethodReturnType) { throw new InvalidOperationException(SR.GetString(SR.ModelDataSourceView_MustUseSelectResultAsReturnType)); } } } if (!String.IsNullOrEmpty(arguments.SortExpression)) { autoSort = IsAutoSortingRequired(method.MethodInfo, isReturningQueryable); } selectResultProcessingOptions = new DataSourceSelectResultProcessingOptions() { ModelType = modelType, AutoPage = autoPage, AutoSort = autoSort }; EvaluateMethodParameters(DataSourceOperation.Select, method, mergedParameters); return method; }
private void SetCancellationTokenIfRequired(ModelDataSourceMethod method, bool isAsyncMethod, CancellationToken? cancellationToken) { string cancellationTokenParameterName; if (isAsyncMethod && IsCancellationRequired(method.MethodInfo, out cancellationTokenParameterName)) { if (null == cancellationToken) { throw new InvalidOperationException(SR.GetString(SR.ModelDataSourceView_CancellationTokenIsNotSupported)); } method.Parameters[cancellationTokenParameterName] = cancellationToken; } }
/// <summary> /// Evaluates the method parameters using model binding. /// </summary> /// <param name="dataSourceOperation">The datasource operation for which parameters are being evaluated.</param> /// <param name="modelDataSourceMethod">The ModelDataSourceMethod object for which the Parameter collection is being evaluated. The MethodInfo property should already be set on this object.</param> /// <param name="controlValues">The values from the data bound control.</param> protected virtual void EvaluateMethodParameters(DataSourceOperation dataSourceOperation, ModelDataSourceMethod modelDataSourceMethod, IDictionary controlValues) { EvaluateMethodParameters(dataSourceOperation, modelDataSourceMethod, controlValues, isPageLoadComplete: false); }
private Func<object, Task> GetSelectAsyncFunc(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback, ModelDataSourceMethod method) { Func<object, Task> func = async _ => { ValidateAsyncModelBindingRequirements(); CancellationTokenSource cancellationTokenSource = _owner.DataControl.Page.CreateCancellationTokenFromAsyncTimeout(); CancellationToken cancellationToken = cancellationTokenSource.Token; DataSourceSelectResultProcessingOptions selectResultProcessingOptions = null; ModelDataSourceMethod modelMethod = EvaluateSelectMethodParameters(arguments, method, true/*isAsyncSelect*/, out selectResultProcessingOptions); SetCancellationTokenIfRequired(modelMethod, true/*isAsyncMethod*/, cancellationToken); ModelDataMethodResult result = InvokeMethod(modelMethod); IEnumerable finalResult = null; if (result.ReturnValue != null) { await (Task)result.ReturnValue; var returnValue = GetPropertyValueByName(result.ReturnValue, "Result"); if (null == returnValue) { // do nothing } // Users needs to use SelectResult as return type to use // custom paging. else if (returnValue is SelectResult) { var viewOperationTask = _viewOperationTask; if (viewOperationTask != null) { await viewOperationTask; } var selectResult = (SelectResult)returnValue; arguments.TotalRowCount = selectResult.TotalRowCount; finalResult = CreateSelectResult(selectResult.Results, true/*isAsyncSelect*/); } else { // The returnValue does not have to run through ProcessSelectMethodResult() as we // don't support auto-paging or auto-sorting when using async select. finalResult = CreateSelectResult(returnValue, true/*isAsyncSelect*/); } } callback(finalResult); if (cancellationToken.IsCancellationRequested) { throw new TimeoutException(SR.GetString(SR.Async_task_timed_out)); } }; return func; }
private ModelDataSourceMethod EvaluateUpdateMethodParameters(IDictionary keys, IDictionary values, IDictionary oldValues, ModelDataSourceMethod method) { if (!CanUpdate) { throw new NotSupportedException(SR.GetString(SR.ModelDataSourceView_UpdateNotSupported)); } 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(oldValues, caseInsensitiveNewValues); MergeDictionaries(keys, caseInsensitiveNewValues); MergeDictionaries(values, caseInsensitiveNewValues); method = method ?? FindMethod(UpdateMethod); EvaluateMethodParameters(DataSourceOperation.Update, method, caseInsensitiveNewValues); return method; }
/// <summary> /// Evaluates the method parameters using model binding. /// </summary> /// <param name="dataSourceOperation">The datasource operation for which parameters are being evaluated.</param> /// <param name="modelDataSourceMethod">The ModelDataSourceMethod object for which the Parameter collection is being evaluated. The MethodInfo property should already be set on this object.</param> /// <param name="controlValues">The values from the data bound control.</param> /// <param name="isPageLoadComplete">This must be set to true only when this method is called in Page's LoadComplete event handler /// to evaluate the select method parameters that use custom value providers so that we can identify any changes /// to those and mark the data-bound control for data binding if necessary.</param> protected virtual void EvaluateMethodParameters(DataSourceOperation dataSourceOperation, ModelDataSourceMethod modelDataSourceMethod, IDictionary controlValues, bool isPageLoadComplete) { Debug.Assert(_owner.DataControl.Page != null); Debug.Assert(_owner.DataControl.TemplateControl != null); MethodInfo actionMethod = modelDataSourceMethod.MethodInfo; IModelBinder binder = ModelBinders.Binders.DefaultBinder; IValueProvider dataBoundControlValueProvider = GetValueProviderFromDictionary(controlValues); ModelBindingExecutionContext modelBindingExecutionContext = _owner.DataControl.Page.ModelBindingExecutionContext; //This is used by ControlValueProvider later. modelBindingExecutionContext.PublishService <Control>(_owner.DataControl); //This is done for the TryUpdateModel to work inside a Data Method. if (dataSourceOperation != DataSourceOperation.Select) { _owner.DataControl.Page.SetActiveValueProvider(dataBoundControlValueProvider); } foreach (ParameterInfo parameterInfo in actionMethod.GetParameters()) { object value = null; string modelName = parameterInfo.Name; if (parameterInfo.ParameterType == typeof(ModelMethodContext)) { //ModelMethodContext is a special parameter we pass in for enabling developer to call //TryUpdateModel when Select/Update/Delete/InsertMethods are on a custom class. value = new ModelMethodContext(_owner.DataControl.Page); } //Do not attempt model binding the out parameters else if (!parameterInfo.IsOut) { bool validateRequest; IValueProvider customValueProvider = GetCustomValueProvider(modelBindingExecutionContext, parameterInfo, ref modelName, out validateRequest); //When we are evaluating the parameter at the time of page load, we do not want to populate the actual ModelState //because there will be another evaluation at data-binding causing duplicate errors if model validation fails. ModelStateDictionary modelState = isPageLoadComplete ? new ModelStateDictionary() : _owner.DataControl.Page.ModelState; ModelBindingContext bindingContext = new ModelBindingContext() { ModelBinderProviders = ModelBinderProviders.Providers, ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterInfo.ParameterType), ModelState = modelState, ModelName = modelName, ValueProvider = customValueProvider, ValidateRequest = validateRequest }; //Select parameters that take custom values providers are tracked by ViewState so that //we can detect any changes from previous page request and mark the data bound control for data binding if necessary. if (dataSourceOperation == DataSourceOperation.Select && customValueProvider != null && parameterInfo.ParameterType.IsSerializable) { if (!SelectParameters.ContainsKey(parameterInfo.Name)) { SelectParameters.Add(parameterInfo.Name, new MethodParameterValue()); } if (binder.BindModel(modelBindingExecutionContext, bindingContext)) { value = bindingContext.Model; } SelectParameters[parameterInfo.Name].UpdateValue(value); } else { if (isPageLoadComplete) { Debug.Assert(dataSourceOperation == DataSourceOperation.Select, "Only Select Operation should have been done immediately after page load"); //When this method is called as part of Page's LoadComplete event handler we do not have values in defaultValueProvider //(i.e., values from DataBoundControl), so we need not evaluate the parameters values. continue; } if (customValueProvider == null) { bindingContext.ValueProvider = dataBoundControlValueProvider; } if (binder.BindModel(modelBindingExecutionContext, bindingContext)) { value = bindingContext.Model; } } if (!isPageLoadComplete) { ValidateParameterValue(parameterInfo, value, actionMethod); } } modelDataSourceMethod.Parameters.Add(parameterInfo.Name, value); } }
private void SelectAsync(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback, ModelDataSourceMethod method) { Func<object, Task> func = GetSelectAsyncFunc(arguments, callback, method); var syncContext = _owner.DataControl.Page.Context.SyncContext as AspNetSynchronizationContext; if (null == syncContext) { throw new InvalidOperationException(SR.GetString(SR.ModelDataSourceView_UseAsyncMethodMustBeUsingAsyncPage)); } // The first edition of the async model binding feature was implemented by registering async binding // function as PageAsyncTask. We, however, decided not to do that because postponing data binding // to page async point changed the order of page events and caused many problems. // See the comment on SynchronizationHelper.QueueAsynchronousAsync for more details regarding to the PostAsync // function. syncContext.PostAsync(func, null); }
/// <summary> /// Invokes the data method in a secure fashion. /// </summary> /// <param name="method"> /// The ModelDataSouceMethod object specifying the Instance on which the method should be invoked (null for static methods), /// the MethodInfo of the method to be invoked and the Parameters for invoking the method. /// All the above properties should be populated before this method is called. /// </param> /// <returns> /// A ModelDataSouceResult object containing the ReturnValue of the method and any out parameters. /// </returns> protected virtual ModelDataMethodResult InvokeMethod(ModelDataSourceMethod method) { return InvokeMethod(method, false/*isAsyncMethod*/); }
// For unit testing. // Return the select async func that we use in the SelectAsync method. internal Func<object, Task> SelectAsyncInternal(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback, ModelDataSourceMethod method) { return GetSelectAsyncFunc(arguments, callback, method); }
private ModelDataMethodResult InvokeMethod(ModelDataSourceMethod method, bool isAsyncMethod) { object returnValue = null; 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]; } } returnValue = _methodInvokerDispatcher(method.MethodInfo, method.Instance, parameterValues); OrderedDictionary outputParameters = GetOutputParameters(method.MethodInfo.GetParameters(), parameterValues); method.Instance = null; // Data Method is done executing, turn off the TryUpdateModel // Do not turn off the TryUpdateModel at this point when the method is async if (!isAsyncMethod) { _owner.DataControl.Page.SetActiveValueProvider(null); } return new ModelDataMethodResult(returnValue, outputParameters); }
/// <summary> /// Evaluates the method parameters using model binding. /// </summary> /// <param name="dataSourceOperation">The datasource operation for which parameters are being evaluated.</param> /// <param name="modelDataSourceMethod">The ModelDataSourceMethod object for which the Parameter collection is being evaluated. The MethodInfo property should already be set on this object.</param> /// <param name="controlValues">The values from the data bound control.</param> /// <param name="isPageLoadComplete">This must be set to true only when this method is called in Page's LoadComplete event handler /// to evaluate the select method parameters that use custom value providers so that we can identify any changes /// to those and mark the data-bound control for data binding if necessary.</param> protected virtual void EvaluateMethodParameters(DataSourceOperation dataSourceOperation, ModelDataSourceMethod modelDataSourceMethod, IDictionary controlValues, bool isPageLoadComplete) { Debug.Assert(_owner.DataControl.Page != null); Debug.Assert(_owner.DataControl.TemplateControl != null); MethodInfo actionMethod = modelDataSourceMethod.MethodInfo; IModelBinder binder = ModelBinders.Binders.DefaultBinder; IValueProvider dataBoundControlValueProvider = GetValueProviderFromDictionary(controlValues); ModelBindingExecutionContext modelBindingExecutionContext = _owner.DataControl.Page.ModelBindingExecutionContext; Control previousDataControl = null; if (BinaryCompatibility.Current.TargetsAtLeastFramework46) { // DevDiv 1087698: a child control overwrites its parent controls's modelBindingExecutionContext, // which may cause a problem for the parent control to find control by controlId. Control dataControl = modelBindingExecutionContext.TryGetService<Control>(); if (dataControl != _owner.DataControl) { previousDataControl = dataControl; } } //This is used by ControlValueProvider later. modelBindingExecutionContext.PublishService<Control>(_owner.DataControl); //This is done for the TryUpdateModel to work inside a Data Method. if (dataSourceOperation != DataSourceOperation.Select) { _owner.DataControl.Page.SetActiveValueProvider(dataBoundControlValueProvider); } var methodParameters = actionMethod.GetParameters(); ParameterInfo lastParameter = null; if (methodParameters.Length > 0) { lastParameter = methodParameters[methodParameters.Length - 1]; } foreach (ParameterInfo parameterInfo in methodParameters) { object value = null; string modelName = parameterInfo.Name; if (parameterInfo.ParameterType == typeof(ModelMethodContext)) { //ModelMethodContext is a special parameter we pass in for enabling developer to call //TryUpdateModel when Select/Update/Delete/InsertMethods are on a custom class. value = new ModelMethodContext(_owner.DataControl.Page); } //Do not attempt model binding the out parameters else if (!parameterInfo.IsOut) { bool validateRequest; IValueProvider customValueProvider = GetCustomValueProvider(modelBindingExecutionContext, parameterInfo, ref modelName, out validateRequest); //When we are evaluating the parameter at the time of page load, we do not want to populate the actual ModelState //because there will be another evaluation at data-binding causing duplicate errors if model validation fails. ModelStateDictionary modelState = isPageLoadComplete ? new ModelStateDictionary() : _owner.DataControl.Page.ModelState; ModelBindingContext bindingContext = new ModelBindingContext() { ModelBinderProviders = ModelBinderProviders.Providers, ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterInfo.ParameterType), ModelState = modelState, ModelName = modelName, ValueProvider = customValueProvider, ValidateRequest = validateRequest }; //Select parameters that take custom values providers are tracked by ViewState so that //we can detect any changes from previous page request and mark the data bound control for data binding if necessary. if (dataSourceOperation == DataSourceOperation.Select && customValueProvider != null && parameterInfo.ParameterType.IsSerializable) { if (!SelectParameters.ContainsKey(parameterInfo.Name)) { SelectParameters.Add(parameterInfo.Name, new MethodParameterValue()); } if (binder.BindModel(modelBindingExecutionContext, bindingContext)) { value = bindingContext.Model; } SelectParameters[parameterInfo.Name].UpdateValue(value); } else { if (isPageLoadComplete) { Debug.Assert(dataSourceOperation == DataSourceOperation.Select, "Only Select Operation should have been done immediately after page load"); //When this method is called as part of Page's LoadComplete event handler we do not have values in defaultValueProvider //(i.e., values from DataBoundControl), so we need not evaluate the parameters values. continue; } if (customValueProvider == null) { bindingContext.ValueProvider = dataBoundControlValueProvider; } if (binder.BindModel(modelBindingExecutionContext, bindingContext)) { value = bindingContext.Model; } } // We set the CancellationToken after EvaluateMethodParameters(). // We don't want to set a null value to a CancellationToken variable. if (parameterInfo == lastParameter && typeof(CancellationToken) == parameterInfo.ParameterType && value == null) { value = CancellationToken.None; } if (!isPageLoadComplete) { ValidateParameterValue(parameterInfo, value, actionMethod); } } modelDataSourceMethod.Parameters.Add(parameterInfo.Name, value); } if (previousDataControl != null) { modelBindingExecutionContext.PublishService<Control>(previousDataControl); } }
private bool RequireAsyncModelBinding(string methodName, out ModelDataSourceMethod method) { if (!AppSettings.EnableAsyncModelBinding) { method = null; return false; } method = FindMethod(methodName); if (null == method) { return false; } MethodInfo methodInfo = method.MethodInfo; bool returnTypeIsTask = typeof(Task).IsAssignableFrom(methodInfo.ReturnType); return returnTypeIsTask; }