e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
200 lines
9.5 KiB
C#
200 lines
9.5 KiB
C#
namespace System.Web.UI.WebControls {
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.Web;
|
|
using System.Linq;
|
|
using System.Web.Compilation;
|
|
using System.Web.UI;
|
|
using System.Web.UI.WebControls;
|
|
using System.Web.Resources;
|
|
using System.Globalization;
|
|
|
|
internal static class DataSourceHelper {
|
|
public static object SaveViewState(ParameterCollection parameters) {
|
|
if (parameters != null) {
|
|
return ((IStateManager)parameters).SaveViewState();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static void TrackViewState(ParameterCollection parameters) {
|
|
if (parameters != null) {
|
|
((IStateManager)parameters).TrackViewState();
|
|
}
|
|
}
|
|
|
|
public static IDictionary<string, object> ToDictionary(this ParameterCollection parameters, HttpContext context, Control control) {
|
|
return ToDictionary(parameters.GetValues(context, control));
|
|
}
|
|
|
|
internal static IDictionary<string, object> ToDictionary(this IOrderedDictionary parameterValues) {
|
|
Dictionary<string, object> values = new Dictionary<string, object>(parameterValues.Count, StringComparer.OrdinalIgnoreCase);
|
|
|
|
foreach (DictionaryEntry entry in parameterValues) {
|
|
values[(string)entry.Key] = entry.Value;
|
|
}
|
|
|
|
return values;
|
|
}
|
|
|
|
public static IOrderedDictionary ToCaseInsensitiveDictionary(this IDictionary dictionary) {
|
|
if (dictionary != null) {
|
|
IOrderedDictionary destination = new OrderedDictionary(dictionary.Count, StringComparer.OrdinalIgnoreCase);
|
|
|
|
foreach (DictionaryEntry de in dictionary) {
|
|
destination[de.Key] = de.Value;
|
|
}
|
|
|
|
return destination;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
internal static object CreateObjectInstance(Type type) {
|
|
// FastCreatePublicInstance is faster than Activator.CreateInstance since it caches the type factories.
|
|
return HttpRuntime.FastCreatePublicInstance(type);
|
|
}
|
|
|
|
public static bool MergeDictionaries(object dataObjectType, ParameterCollection referenceValues, IDictionary source,
|
|
IDictionary destination, IDictionary<string, Exception> validationErrors) {
|
|
return MergeDictionaries(dataObjectType, referenceValues, source, destination, null, validationErrors);
|
|
}
|
|
|
|
public static bool MergeDictionaries(object dataObjectType, ParameterCollection reference, IDictionary source,
|
|
IDictionary destination, IDictionary destinationCopy, IDictionary<string, Exception> validationErrors) {
|
|
if (source != null) {
|
|
foreach (DictionaryEntry de in source) {
|
|
object value = de.Value;
|
|
// search for a parameter that corresponds to this dictionary entry.
|
|
Parameter referenceParameter = null;
|
|
string parameterName = (string)de.Key;
|
|
foreach (Parameter p in reference) {
|
|
if (String.Equals(p.Name, parameterName, StringComparison.OrdinalIgnoreCase)) {
|
|
referenceParameter = p;
|
|
break;
|
|
}
|
|
}
|
|
// use the parameter for type conversion, default value and/or converting empty string to null.
|
|
if (referenceParameter != null) {
|
|
try {
|
|
value = referenceParameter.GetValue(value, true);
|
|
}
|
|
catch (Exception e) {
|
|
// catch conversion exceptions so they can be handled. Note that conversion throws various
|
|
// types of exceptions like InvalidCastException, FormatException, OverflowException, etc.
|
|
validationErrors[referenceParameter.Name] = e;
|
|
}
|
|
}
|
|
// save the value to the merged dictionaries.
|
|
destination[parameterName] = value;
|
|
if (destinationCopy != null) {
|
|
destinationCopy[parameterName] = value;
|
|
}
|
|
}
|
|
}
|
|
return validationErrors.Count == 0;
|
|
}
|
|
|
|
public static Type GetType(string typeName) {
|
|
return BuildManager.GetType(typeName, true /* throwOnError */, true /* ignoreCase */);
|
|
}
|
|
|
|
private static object ConvertType(object value, Type type, string paramName) {
|
|
// NOTE: This method came from ObjectDataSource with no changes made.
|
|
string s = value as string;
|
|
if (s != null) {
|
|
// Get the type converter for the destination type
|
|
TypeConverter converter = TypeDescriptor.GetConverter(type);
|
|
if (converter != null) {
|
|
// Perform the conversion
|
|
try {
|
|
value = converter.ConvertFromString(s);
|
|
}
|
|
catch (NotSupportedException) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_CannotConvertType, paramName, typeof(string).FullName,
|
|
type.FullName));
|
|
}
|
|
catch (FormatException) {
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_CannotConvertType, paramName, typeof(string).FullName,
|
|
type.FullName));
|
|
}
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public static object BuildDataObject(Type dataObjectType, IDictionary inputParameters, IDictionary<string, Exception> validationErrors) {
|
|
object dataObject = CreateObjectInstance(dataObjectType);
|
|
|
|
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(dataObject);
|
|
foreach (DictionaryEntry de in inputParameters) {
|
|
string propName = (de.Key == null ? String.Empty : de.Key.ToString());
|
|
PropertyDescriptor property = props.Find(propName, /*ignoreCase*/true);
|
|
// NOTE: No longer throws when a property is not found or is read only. This makes
|
|
// Delete, Insert and Update operations more optimistic, allowing scenarios such as:
|
|
// 1) Deletes and Updates after projecting data in the Selecting event.
|
|
// 2) Deletes and Updates after selecting children of the data object type in the
|
|
// Selecting event.
|
|
if ((property != null) && (!property.IsReadOnly)) {
|
|
try {
|
|
object value = BuildObjectValue(de.Value, property.PropertyType, propName);
|
|
property.SetValue(dataObject, value);
|
|
}
|
|
catch (Exception e) {
|
|
validationErrors[property.Name] = e;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (validationErrors.Any()) {
|
|
return null;
|
|
}
|
|
|
|
return dataObject;
|
|
}
|
|
|
|
internal static object BuildObjectValue(object value, Type destinationType, string paramName) {
|
|
// NOTE: This method came from ObjectDataSource with no changes made.
|
|
// 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<DateTime>
|
|
|
|
// 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<T>
|
|
if (isNullable) {
|
|
Type paramValueType = value.GetType();
|
|
if (innerDestinationType != paramValueType) {
|
|
// Throw if for example, we are trying to convert from int to Nullable<bool>
|
|
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
|
|
AtlasWeb.LinqDataSourceView_CannotConvertType, paramName, paramValueType.FullName,
|
|
String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>",
|
|
destinationType.GetGenericArguments()[0].FullName)));
|
|
}
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
}
|