From 8b457a0bb6a93c89a1c36619ff9a9c51423165f5 Mon Sep 17 00:00:00 2001 From: Maximilian Date: Mon, 12 Feb 2018 15:18:23 +0100 Subject: [PATCH 1/4] Upgraded main aspnet core project to 2.0 --- ...Query.DataTables.AspNetCore.Example.csproj | 86 ++----------------- .../DataTablesModelBinder.cs | 38 +++++++- .../Mvc.JQuery.DataTables.AspNetCore.csproj | 8 +- .../Mvc.JQuery.DataTables.Common.csproj | 8 +- .../Mvc.JQuery.Datatables.Templates.csproj | 8 +- 5 files changed, 53 insertions(+), 95 deletions(-) diff --git a/Mvc.JQuery.DataTables.AspNetCore.Example/Mvc.JQuery.DataTables.AspNetCore.Example.csproj b/Mvc.JQuery.DataTables.AspNetCore.Example/Mvc.JQuery.DataTables.AspNetCore.Example.csproj index 001d716..c2ad9ea 100644 --- a/Mvc.JQuery.DataTables.AspNetCore.Example/Mvc.JQuery.DataTables.AspNetCore.Example.csproj +++ b/Mvc.JQuery.DataTables.AspNetCore.Example/Mvc.JQuery.DataTables.AspNetCore.Example.csproj @@ -1,94 +1,18 @@  - netcoreapp1.0 + netcoreapp2.0 - $(PackageTargetFallback);portable-net45+win8+wp8+wpa81; Mvc.JQuery.DataTables.Example - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/Mvc.JQuery.DataTables.AspNetCore/DataTablesModelBinder.cs b/Mvc.JQuery.DataTables.AspNetCore/DataTablesModelBinder.cs index 7cb2650..8a4ab8b 100644 --- a/Mvc.JQuery.DataTables.AspNetCore/DataTablesModelBinder.cs +++ b/Mvc.JQuery.DataTables.AspNetCore/DataTablesModelBinder.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Internal; using System; using System.Threading.Tasks; @@ -99,9 +100,42 @@ private DataTablesParam BindLegacyModel(IValueProvider valueProvider, int column private static T GetValue(IValueProvider valueProvider, string key) { ValueProviderResult valueResult = valueProvider.GetValue(key); - return (valueResult==null) + return (valueResult == null) ? default(T) - : (T)valueResult.ConvertTo(typeof(T)); + : ConvertTo(valueResult); + } + + /// + /// Attempts to convert the values in to the specified type. + /// + /// The for conversion. + /// The . + /// + /// The converted value, or the default value of if the value could not be converted. + /// + /// + /// Copyright (c) .NET Foundation and Contributors + /// All rights reserved. + /// Licensed under the Apache License, Version 2.0 (the "License"); you may not use + /// this file except in compliance with the License.You may obtain a copy of the license at: + /// http://www.apache.org/licenses/LICENSE-2.0 + /// Unless required by applicable law or agreed to in writing, software distributed + /// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + /// CONDITIONS OF ANY KIND, either express or implied. See the License for the + /// specific language governing permissions and limitations under the License. + /// + private static T ConvertTo(ValueProviderResult result) + { + object valueToConvert = null; + if (result.Values.Count == 1) + { + valueToConvert = result.Values[0]; + } + else if (result.Values.Count > 1) + { + valueToConvert = result.Values.ToArray(); + } + return ModelBindingHelper.ConvertTo(valueToConvert, result.Culture); } } diff --git a/Mvc.JQuery.DataTables.AspNetCore/Mvc.JQuery.DataTables.AspNetCore.csproj b/Mvc.JQuery.DataTables.AspNetCore/Mvc.JQuery.DataTables.AspNetCore.csproj index 5cbede3..f741182 100644 --- a/Mvc.JQuery.DataTables.AspNetCore/Mvc.JQuery.DataTables.AspNetCore.csproj +++ b/Mvc.JQuery.DataTables.AspNetCore/Mvc.JQuery.DataTables.AspNetCore.csproj @@ -1,7 +1,7 @@  - netstandard1.6;net451 + netstandard2.0 Mvc.JQuery.DataTables Mvc.JQuery.DataTables.AspNetCore Mvc.JQuery.DataTables.AspNetCore @@ -16,9 +16,9 @@ https://github.com/mcintyre321/mvc.jquery.datatables/blob/master/License.txt - - - + + + diff --git a/Mvc.JQuery.DataTables.Common/Mvc.JQuery.DataTables.Common.csproj b/Mvc.JQuery.DataTables.Common/Mvc.JQuery.DataTables.Common.csproj index 81bfe7a..4e1cb47 100644 --- a/Mvc.JQuery.DataTables.Common/Mvc.JQuery.DataTables.Common.csproj +++ b/Mvc.JQuery.DataTables.Common/Mvc.JQuery.DataTables.Common.csproj @@ -24,10 +24,10 @@ - - - - + + + + diff --git a/Mvc.JQuery.Datatables.Templates/Mvc.JQuery.Datatables.Templates.csproj b/Mvc.JQuery.Datatables.Templates/Mvc.JQuery.Datatables.Templates.csproj index a8183bc..3bc7a4c 100644 --- a/Mvc.JQuery.Datatables.Templates/Mvc.JQuery.Datatables.Templates.csproj +++ b/Mvc.JQuery.Datatables.Templates/Mvc.JQuery.Datatables.Templates.csproj @@ -12,10 +12,10 @@ - - - - + + + + From f3f94c4d07d7ef06b4b0ba63ef37be9e60ff9628 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 9 Sep 2019 09:34:50 +0200 Subject: [PATCH 2/4] Convert range filter dates to universaltime All dates in the datetime filter were converted to UTC prior to selecting them from the database. Range filters were not considered however, leading to missing entries. --- Mvc.JQuery.DataTables.Common/Processing/TypeFilters.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Mvc.JQuery.DataTables.Common/Processing/TypeFilters.cs b/Mvc.JQuery.DataTables.Common/Processing/TypeFilters.cs index c230ff7..ea17f90 100644 --- a/Mvc.JQuery.DataTables.Common/Processing/TypeFilters.cs +++ b/Mvc.JQuery.DataTables.Common/Processing/TypeFilters.cs @@ -111,12 +111,14 @@ public static string DateTimeOffsetFilter(string query, string columnname, DataT DateTimeOffset start, end; if (DateTimeOffset.TryParse(parts[0] ?? "", out start)) { + start = start.ToUniversalTime(); filterString = columnname + " >= @" + parametersForLinqQuery.Count; parametersForLinqQuery.Add(start); } if (DateTimeOffset.TryParse(parts[1] ?? "", out end)) { + end = end.ToUniversalTime(); filterString = (filterString == null ? null : filterString + " and ") + columnname + " <= @" + parametersForLinqQuery.Count; parametersForLinqQuery.Add(end); } @@ -161,12 +163,14 @@ public static string DateTimeFilter(string query, string columnname, DataTablesP DateTime start, end; if (DateTime.TryParse(parts[0] ?? "", out start)) { + start = start.ToUniversalTime(); filterString = columnname + " >= @" + parametersForLinqQuery.Count; parametersForLinqQuery.Add(start); } if (DateTime.TryParse(parts[1] ?? "", out end)) { + end = end.ToUniversalTime(); filterString = (filterString == null ? null : filterString + " and ") + columnname + " <= @" + parametersForLinqQuery.Count; parametersForLinqQuery.Add(end); } @@ -254,4 +258,4 @@ public static string EnumFilter(string q, string columnname, DataTablesPropertyI return columnname + " == @" + (parametersForLinqQuery.Count - 1); } } -} \ No newline at end of file +} From 6e779063918aa1ff7816dd8aee18a62b96cf57d3 Mon Sep 17 00:00:00 2001 From: jandic Date: Tue, 22 Oct 2019 11:51:57 +0200 Subject: [PATCH 3/4] Fix for an issue with data table filtering and allowing for user defined filters (#175) * Update DataTablesFiltering.cs Fixed an issue when filtering on a data table throws an exception in cases there are no relevant columns to be filtered. Example: data table contains only numerical columns and a user types 'a letter'. Since the letter cannot be converted to a number, no where clause is generated and data.Where command was failing. * Allowing for custom filter definition Allowing for custom filter definitions by a user and fixing a bug in RegisterFilter method. * Fix for EnumFilter EnumFilter method was crashing when a value to search was not the exact enum value. This prevented any subsequent filters to be processed. --- .../DataTablesFiltering.cs | 10 +++++++--- .../Processing/TypeFilters.cs | 16 +++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Mvc.JQuery.DataTables.Common/DataTablesFiltering.cs b/Mvc.JQuery.DataTables.Common/DataTablesFiltering.cs index 1a9cb4f..0d2ce61 100644 --- a/Mvc.JQuery.DataTables.Common/DataTablesFiltering.cs +++ b/Mvc.JQuery.DataTables.Common/DataTablesFiltering.cs @@ -7,7 +7,7 @@ namespace Mvc.JQuery.DataTables { - internal class DataTablesFiltering + public class DataTablesFiltering { public IQueryable ApplyFiltersAndSort(DataTablesParam dtParameters, IQueryable data, DataTablesPropertyInfo[] columns) { @@ -30,7 +30,11 @@ public IQueryable ApplyFiltersAndSort(DataTablesParam dtParameters, IQuery } } var values = parts.Where(p => p != null); - data = data.Where(string.Join(" or ", values), parameters.ToArray()); + var filterClause = string.Join(" or ", values); + if (string.IsNullOrWhiteSpace(filterClause) == false) + { + data = data.Where(filterClause, parameters.ToArray()); + } } for (int i = 0; i < dtParameters.sSearchValues.Count; i++) { @@ -114,7 +118,7 @@ private static ReturnedFilteredQueryForType Guard(Func(GuardedFilter filter) { - Filters.Add(Guard(arg => arg is T, filter)); + Filters.Add(Guard(arg => arg.Type == typeof(T), filter)); } private static string GetFilterClause(string query, DataTablesPropertyInfo column, List parametersForLinqQuery) diff --git a/Mvc.JQuery.DataTables.Common/Processing/TypeFilters.cs b/Mvc.JQuery.DataTables.Common/Processing/TypeFilters.cs index ea17f90..0ba2111 100644 --- a/Mvc.JQuery.DataTables.Common/Processing/TypeFilters.cs +++ b/Mvc.JQuery.DataTables.Common/Processing/TypeFilters.cs @@ -251,11 +251,17 @@ public static string StringFilter(string q, string columnname, DataTablesPropert public static string EnumFilter(string q, string columnname, DataTablesPropertyInfo propertyInfo, List parametersForLinqQuery) { - - if (q.StartsWith("^")) q = q.Substring(1); - if (q.EndsWith("$")) q = q.Substring(0, q.Length - 1); - parametersForLinqQuery.Add(ParseValue(q, propertyInfo.Type)); - return columnname + " == @" + (parametersForLinqQuery.Count - 1); + try + { + if (q.StartsWith("^")) q = q.Substring(1); + if (q.EndsWith("$")) q = q.Substring(0, q.Length - 1); + parametersForLinqQuery.Add(ParseValue(q, propertyInfo.Type)); + return columnname + " == @" + (parametersForLinqQuery.Count - 1); + } + catch (Exception) + { + return null; + } } } } From 730f32be0c5a22611351f7e04abce12fe152d640 Mon Sep 17 00:00:00 2001 From: Raymen Scholten Date: Tue, 31 Mar 2020 15:00:16 +0200 Subject: [PATCH 4/4] Support asp.net core 3.1 (#178) --- .../DataTablesModelBinder.cs | 1 - .../Extensions.cs | 10 +- .../ModelBindingHelper.cs | 181 ++++++++++++++++++ .../Mvc.JQuery.DataTables.AspNetCore.csproj | 14 +- 4 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 Mvc.JQuery.DataTables.AspNetCore/ModelBindingHelper.cs diff --git a/Mvc.JQuery.DataTables.AspNetCore/DataTablesModelBinder.cs b/Mvc.JQuery.DataTables.AspNetCore/DataTablesModelBinder.cs index 8a4ab8b..81bae70 100644 --- a/Mvc.JQuery.DataTables.AspNetCore/DataTablesModelBinder.cs +++ b/Mvc.JQuery.DataTables.AspNetCore/DataTablesModelBinder.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Mvc.ModelBinding.Internal; using System; using System.Threading.Tasks; diff --git a/Mvc.JQuery.DataTables.AspNetCore/Extensions.cs b/Mvc.JQuery.DataTables.AspNetCore/Extensions.cs index 073eb43..e9ef853 100644 --- a/Mvc.JQuery.DataTables.AspNetCore/Extensions.cs +++ b/Mvc.JQuery.DataTables.AspNetCore/Extensions.cs @@ -5,6 +5,9 @@ using System.Reflection; using Microsoft.AspNetCore.Mvc; using Mvc.JQuery.DataTables; +#if NETCOREAPP3_1 +using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation; +#endif namespace Microsoft.Extensions.DependencyInjection { @@ -20,7 +23,12 @@ public static IServiceCollection AddMvcJQueryDataTables(this IServiceCollection dataTablesViewModelType.Namespace + ".Common"), }; services.AddSingleton(settings); +#if NETCOREAPP3_1 + services.Configure(s => s.FileProviders.Add(settings.FileProvider)); +#elif NETSTANDARD2_0 services.Configure(s => s.FileProviders.Add(settings.FileProvider)); +#endif + services.AddMvc(options => { options.UseHtmlEncodeModelBinding(); }); return services; @@ -46,7 +54,7 @@ public static class MvcJQueryDataTablesExtensions public static IApplicationBuilder UseMvcJQueryDataTables(this IApplicationBuilder app) { var settings = app.ApplicationServices.GetService(); - if(settings == null) + if (settings == null) { throw new InvalidOperationException("Unable to find the required services. Please add all the required services by calling 'IServiceCollection.{}' inside the call to 'ConfigureServices(...)' in the application startup code."); } diff --git a/Mvc.JQuery.DataTables.AspNetCore/ModelBindingHelper.cs b/Mvc.JQuery.DataTables.AspNetCore/ModelBindingHelper.cs new file mode 100644 index 0000000..aa4637d --- /dev/null +++ b/Mvc.JQuery.DataTables.AspNetCore/ModelBindingHelper.cs @@ -0,0 +1,181 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections; +using System.ComponentModel; +using System.Globalization; +using System.Reflection; +using System.Runtime.ExceptionServices; + +namespace Mvc.JQuery.DataTables +{ + internal static class ModelBindingHelper + { + /// + /// Converts the provided to a value of . + /// + /// The for conversion. + /// The value to convert."/> + /// The for conversion. + /// + /// The converted value or the default value of if the value could not be converted. + /// + public static T ConvertTo(object value, CultureInfo culture) + { + var converted = ConvertTo(value, typeof(T), culture); + return converted == null ? default(T) : (T)converted; + } + + /// + /// Converts the provided to a value of . + /// + /// The value to convert."/> + /// The for conversion. + /// The for conversion. + /// + /// The converted value or null if the value could not be converted. + /// + public static object ConvertTo(object value, Type type, CultureInfo culture) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (value == null) + { + // For value types, treat null values as though they were the default value for the type. + return type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null; + } + + if (type.IsAssignableFrom(value.GetType())) + { + return value; + } + + var cultureToUse = culture ?? CultureInfo.InvariantCulture; + return UnwrapPossibleArrayType(value, type, cultureToUse); + } + + private static object UnwrapPossibleArrayType(object value, Type destinationType, CultureInfo culture) + { + // array conversion results in four cases, as below + var valueAsArray = value as Array; + if (destinationType.IsArray) + { + var destinationElementType = destinationType.GetElementType(); + if (valueAsArray != null) + { + // case 1: both destination + source type are arrays, so convert each element + var converted = (IList)Array.CreateInstance(destinationElementType, valueAsArray.Length); + for (var i = 0; i < valueAsArray.Length; i++) + { + converted[i] = ConvertSimpleType(valueAsArray.GetValue(i), destinationElementType, culture); + } + return converted; + } + else + { + // case 2: destination type is array but source is single element, so wrap element in + // array + convert + var element = ConvertSimpleType(value, destinationElementType, culture); + var converted = (IList)Array.CreateInstance(destinationElementType, 1); + converted[0] = element; + return converted; + } + } + else if (valueAsArray != null) + { + // case 3: destination type is single element but source is array, so extract first element + convert + if (valueAsArray.Length > 0) + { + value = valueAsArray.GetValue(0); + return ConvertSimpleType(value, destinationType, culture); + } + else + { + // case 3(a): source is empty array, so can't perform conversion + return null; + } + } + + // case 4: both destination + source type are single elements, so convert + return ConvertSimpleType(value, destinationType, culture); + } + + private static object ConvertSimpleType(object value, Type destinationType, CultureInfo culture) + { + if (value == null || destinationType.IsAssignableFrom(value.GetType())) + { + return value; + } + + // In case of a Nullable object, we try again with its underlying type. + destinationType = UnwrapNullableType(destinationType); + + // if this is a user-input value but the user didn't type anything, return no value + if (value is string valueAsString && string.IsNullOrWhiteSpace(valueAsString)) + { + return null; + } + + var converter = TypeDescriptor.GetConverter(destinationType); + var canConvertFrom = converter.CanConvertFrom(value.GetType()); + if (!canConvertFrom) + { + converter = TypeDescriptor.GetConverter(value.GetType()); + } + if (!(canConvertFrom || converter.CanConvertTo(destinationType))) + { + // EnumConverter cannot convert integer, so we verify manually + if (destinationType.GetTypeInfo().IsEnum && + (value is int || + value is uint || + value is long || + value is ulong || + value is short || + value is ushort || + value is byte || + value is sbyte)) + { + return Enum.ToObject(destinationType, value); + } + + throw new InvalidOperationException($"NoConverterExists: {value.GetType()} -> {destinationType}"); + } + + try + { + return canConvertFrom + ? converter.ConvertFrom(null, culture, value) + : converter.ConvertTo(null, culture, value, destinationType); + } + catch (FormatException) + { + throw; + } + catch (Exception ex) + { + if (ex.InnerException == null) + { + throw; + } + else + { + // TypeConverter throws System.Exception wrapping the FormatException, + // so we throw the inner exception. + ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + + // This code is never reached because the previous line will always throw. + throw; + } + } + } + + private static Type UnwrapNullableType(Type destinationType) + { + return Nullable.GetUnderlyingType(destinationType) ?? destinationType; + } + } +} \ No newline at end of file diff --git a/Mvc.JQuery.DataTables.AspNetCore/Mvc.JQuery.DataTables.AspNetCore.csproj b/Mvc.JQuery.DataTables.AspNetCore/Mvc.JQuery.DataTables.AspNetCore.csproj index f741182..523ea5d 100644 --- a/Mvc.JQuery.DataTables.AspNetCore/Mvc.JQuery.DataTables.AspNetCore.csproj +++ b/Mvc.JQuery.DataTables.AspNetCore/Mvc.JQuery.DataTables.AspNetCore.csproj @@ -1,21 +1,27 @@  - netstandard2.0 + netcoreapp3.1;netstandard2.0 Mvc.JQuery.DataTables Mvc.JQuery.DataTables.AspNetCore Mvc.JQuery.DataTables.AspNetCore - 1.0.0 + 2.0.0 Harry McIntyre Popular lib for using DataTables.net with IQueryable. Install this package to use with AspNetCore false https://github.com/mcintyre321/mvc.jquery.datatables Harry McIntyre jquery datatables iqueryable razor asp mvc mvc5 - https://github.com/mcintyre321/mvc.jquery.datatables/blob/master/License.txt + https://github.com/mcintyre321/mvc.jquery.datatables/blob/master/License.txt + - + + + + + +