FlexFetcher est une bibliothèque .NET pour le filtrage, le tri, les données de pagination. Il est conçu sur la base des principes OOP et peut être utilisé dans n'importe quel projet .NET: Web, bureau, mobile, etc. FlexFetcher s'inspire du format Telerik Kendo UI Grid.
Il y a beaucoup de grandes bibliothèques pour le filtrage, le tri, la pagination de données dans .NET: Sieve, Querykit, LightQuery, etc. Mais la plupart d'entre elles ne sont pas conçues sur la base des principes OOP. Ils ont des syntaxes de requête qui sont destinées à être lisibles par l'homme, comme (tous les exemples sont tirés de la documentation de ces bibliothèques):
sorts=LikeCount,CommentCount,-created&filters=LikeCount>10,Title@=awesome title,&page=1&pageSize=10
ou
""(Age ^^ [20, 30, 40]) && (BirthMonth ^^* ["January", "February", "March"]) || (Id ^^ ["6d623e92-d2cf-4496-a2df-f49fa77328ee"])""
ou
`?sort=country&thenSort=email desc`
Mais en même temps:
FlexFetcher n'est ni meilleur ni pire que ces bibliothèques, c'est juste différent. Il accepte les requêtes dans un format d'objets, qui peut être sérialisé / désérialisé en JSON comme ceci:
?Filters={"Logic":"And","Filters":[{"Operator":"Eq","Field":"Address.Town","Value":"New York"}]}
Ou, si vous préférez le format plus compact, même comme ceci:
?Filter={"L":"And","Fs":[{"O":"Eq","F":"Address.Town","V":"New York"}]}
Ou, si vous souhaitez utiliser la demande de post (style RPC), tout comme ceci:
{
"Filters" : {
"Logic" : " and " ,
"Filters" : [
{
"Operator" : " eq " ,
"Field" : " Address.Town " ,
"Value" : " New York "
}
]
}
}Ce format est facile à lire et à comprendre pour les humains, facile à étendre, facile à sérialiser / désérialiser, et facile à utiliser dans la communication machine à machine.
FlexFetcher est construit pour les prochaines plates-formes:
Cela signifie que vous pouvez l'utiliser dans les projets .NET Core (voir samples/WebApiSample ) et .NET (voir samples/WebApiSample.Framework48 ).
FlexFetcher prend en charge les prochains types de données pour les champs utilisés dans les filtres et les trieurs:
Toutes les valeurs peuvent être nullables.
Vous pouvez installer FlexFetcher (NuGet) via la console NuGet Package Manager en exécutant la commande suivante:
dotnet add package FlexFetcher
Pour installer flexfetcher.dependencyInjection.microsoft (NuGet):
dotnet add package FlexFetcher.DependencyInjection.Microsoft
Pour installer flexfetcher.serialization.newtonsoftjson (Nuget):
dotnet add package FlexFetcher.Serialization.NewtonsoftJson
Pour installer flexFetcher.serialization.SystemTextJson (NuGet):
dotnet add package FlexFetcher.Serialization.SystemTextJson
Tous les exemples sont effectués sur l'ensemble de données de test, qui est défini dans
tests/TestData/InMemoryDataHelper.cset se compose detests/TestData/Database/PeopleEntity.csettests/TestData/Database/AddressEntity.csentités.
La façon la plus simple d'utiliser FlexFetcher est d'utiliser des méthodes d'extension pour les interfaces IQueryable<T> et IEnumerable<T> .
var filter = new DataFilter
{
Filters = new List < DataFilter >
{
new ( )
{
Field = "Name" ,
Operator = DataFilterOperator . Equal ,
Value = "John"
}
}
} ;
var result = _ctx . People . FilterData ( filter ) . ToList ( ) ; var sorter = new DataSorters
{
Sorters = new List < DataSorter >
{
new DataSorter // First sort by Surname in ascending order
{
Field = "Surname" ,
Direction = DataSorterDirection . Asc
} ,
new DataSorter // Then sort by Name in descending order
{
Field = "Name" ,
Direction = DataSorterDirection . Desc
}
}
} ;
var result = _ctx . People . SortData ( sorter ) . ToList ( ) ; var pager = new DataPager { PageSize = 3 , Page = 1 } ; // Numeration starts from 1 for Page number
OR
var pager = new DataPager { Skip = 3 , Take = 3 } ;
var result = _ctx . People . PageData ( pager ) . ToList ( ) ; Les méthodes d'extensions sont bonnes pour les cas simples, mais leur utilisation est très limitée.
Pour les cas plus complexes, vous pouvez utiliser des classes FlexFetcher : FlexFilter<TEntity> et FlexFilter<TEntity, TModel> , FlexSorter<TEntity> et FlexSorter<TEntity, TModel> , FlexPager<TEntity> et FlexPager<TEntity, TModel> , FlexFetcher<TEntity> et FlexFetcher<TEntity, TModel> .
Même si ce n'est pas un moyen recommandé, mais pour plus de clarté, voyons comment créer des instances de classes manuellement. Nous examinerons l'injection de dépendance dans la section correspondante plus tard.
var filter = new DataFilter
{
Filters = new List < DataFilter >
{
new ( )
{
Field = "Name" ,
Operator = DataFilterOperator . Equal ,
Value = "John"
}
}
} ;
var flexFilter = new FlexFilter < PeopleEntity > ( ) ;
var result = flexFilter . FilterData ( _ctx . People , filter ) . ToList ( ) ; var sorters = new DataSorters
{
Sorters = new List < DataSorter >
{
new DataSorter
{
Field = "Surname" ,
Direction = DataSorterDirection . Asc
}
}
} ;
var flexSorter = new FlexSorter < PeopleEntity > ( ) ;
var result = flexSorter . SortData ( _ctx . People , sorters ) . ToList ( ) ; var pager = new DataPager { PageSize = 3 , Page = 1 } ;
var flexPager = new FlexPager < PeopleEntity > ( ) ;
var result = flexPager . PageData ( _ctx . People , pager ) . ToList ( ) ; var pager = new DataPager { PageSize = 3 , Page = 1 } ;
var flexFetcher = new FlexFetcher < PeopleEntity > ( ) ;
var result = flexFetcher . FetchData ( _ctx . People , null , null , pager ) . ToList ( ) ; // Filter, sorter and pager parameters are optional Afin d'utiliser FlexFetcher avec une injection de dépendance, n'oubliez pas d'installer FlexFetcher.DependencyInjection.Microsoft .
Il est possible d'injecter la classe FlexFetcher principale ainsi que ses composants: flexfilter, flexsorter, flexpager. L'utilisation de base est:
services . AddSingleton < FlexFetcher < PeopleEntity > > ( ) ;Les classes FlexFetcher n'ont pas d'état, il est donc sûr de les utiliser comme singletons. Mais si vous voulez les utiliser comme dans la portée ou transitoire, c'est à vous.
Un remplissage plus avancé est affiché ensuite. Voir également plus d'exemples dans tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs , samples/WebApiSample ) et samples/WebApiSample.Framework48 .
Dans notre exemple de modèle de données, nous avons des objets imbriqués: la Sentité des personnes a une propriété d'adressage. Voyons comment filtrer par objet imbriqué:
var filter = new DataFilter
{
Filters = new List < DataFilter >
{
new ( )
{
Field = "Address.City" , // Address is a nested object, so we use dot notation
Operator = DataFilterOperator . Equal ,
Value = "New York"
}
}
} ;
var flexAddressFilter = new FlexFilter < AddressEntity > ( ) ;
var peopleFilterOptions = new FlexFilterOptions < PeopleEntity > ( ) ;
peopleFilterOptions . AddNestedFlexFilter ( flexAddressFilter ) ;
var flexPeopleFilter = new FlexFilter < PeopleEntity > ( peopleFilterOptions ) ;
var result = flexPeopleFilter . FilterData ( _ctx . People , filter ) . ToList ( ) ;La même chose peut être faite avec l'injection de dépendance:
Services . AddSingleton < FlexFilter < AddressEntity > > ( ) ;
Services . AddSingletonFlexOptions < FlexFilterOptions < PeopleEntity > > ( ( provider , options ) =>
{
options . AddNestedFlexFilter ( provider . GetRequiredService < FlexFilter < AddressEntity > > ( ) ) ;
} ) ;
Services . AddSingleton < FlexFilter < PeopleEntity > > ( ) ;Le même principe peut être appliqué à Flexsorter, FlexPager et FlexFetcher.
Voir plus d'exemples dans tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs et samples/WebApiSample .
Dans des exemples précédents, nous n'avons utilisé qu'un seul filtre, mais il est possible d'utiliser plusieurs filtres avec ou ou et des logiques comme celle-ci:
var filter = new DataFilter
{
Logic = DataFilterLogic . Or ,
Filters = new List < DataFilter >
{
new ( )
{
Field = "Name" ,
Operator = DataFilterOperator . Equal ,
Value = "John"
} ,
new ( )
{
Logic = DataFilterLogic . And ,
Filters = new List < DataFilter >
{
new ( )
{
Field = "Name" ,
Operator = DataFilterOperator . Equal ,
Value = "Jane"
} ,
new ( )
{
Field = "Age" ,
Operator = DataFilterOperator . GreaterThan ,
Value = 55
}
}
}
}
} ;FlexFilter prend en charge les filtres imbriqués avec n'importe quelle profondeur.
Si la logique n'est pas spécifiée, elle sera définie sur et par défaut.
Le filtre peut contenir des propriétés (filtres et logique) ou (champ, opérateur et valeur), mais pas les deux.
Nous avons déjà vu des exemples avec des opérateurs égaux et plus grands, mais il y a plus d'opérateurs disponibles:
new DataFilter { Field = "Name" , Operator = DataFilterOperator . Equal , Value = "John" } new DataFilter { Field = "Name" , Operator = DataFilterOperator . NotEqual , Value = "John" } new DataFilter { Field = "Age" , Operator = DataFilterOperator . GreaterThan , Value = 55 } new DataFilter { Field = "Age" , Operator = DataFilterOperator . GreaterThanOrEqual , Value = 55 } new DataFilter { Field = "Age" , Operator = DataFilterOperator . LessThan , Value = 55 } new DataFilter { Field = "Age" , Operator = DataFilterOperator . LessThanOrEqual , Value = 55 } new DataFilter { Field = "Name" , Operator = DataFilterOperator . Contains , Value = "Jo" } new DataFilter { Field = "Name" , Operator = DataFilterOperator . StartsWith , Value = "Jo" } new DataFilter { Field = "Name" , Operator = DataFilterOperator . EndsWith , Value = "hn" } new DataFilter { Field = "Age" , Operator = DataFilterOperator . In , Value = new List < int > { 55 , 56 , 57 } } Afin de créer son propre opérateur de filtre, il est nécessaire:
BaseFilterExpressionHandlerFilterExpressionBuilderAddCustomExpressionHandlers dans la classe FilterExpressionBuilder personnalisée Cela peut ressembler à ceci (voir tests/FlexFetcherTests/FlexFilterTests/CustomFilterExpressionBuilderTests.cs ):
class CustomExpressionBuilderWithValueTest : FilterExpressionBuilder < PeopleEntity >
{
protected override void AddCustomExpressionHandlers ( List < IFilterExpressionHandler > handlers )
{
handlers . Add ( new ModuleFilterExpressionHandler ( ) ) ;
}
private class ModuleFilterExpressionHandler : BaseFilterExpressionHandler
{
public override string Operator => "MODULE" ;
public override Expression BuildExpression ( Expression property , DataFilter filter )
{
var value = BuildValueExpression ( filter ) ;
return Expression . Equal ( Expression . Modulo ( property , value ) , Expression . Constant ( 0 ) ) ;
}
}
}
var customExpressionBuilder = new CustomExpressionBuilderWithValueTest ( ) ;
var options = new FlexFilterOptions < PeopleEntity > ( customExpressionBuilder ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;
var filter = new DataFilter
{
Logic = DataFilterLogic . And ,
Filters = new List < DataFilter >
{
new ( )
{
Field = "Age" ,
Operator = "Module" ,
Value = 15
}
}
} ;
var result = flexFilter . FilterData ( _ctx . People , filter ) . ToList ( ) ;Il est également possible de créer un opérateur de filtre personnalisé qui a besoin de valeur du tout:
class CustomExpressionBuilderWithoutValueTest : FilterExpressionBuilder < PeopleEntity >
{
protected override void AddCustomExpressionHandlers ( List < IFilterExpressionHandler > handlers )
{
handlers . Add ( new EvenNumberFilterExpressionHandler ( ) ) ;
}
private class EvenNumberFilterExpressionHandler : BaseFilterExpressionHandler
{
public override string Operator => "EVEN" ;
public override Expression BuildExpression ( Expression property , DataFilter filter )
{
return Expression . Equal ( Expression . Modulo ( property , Expression . Constant ( 2 , property . Type ) ) , Expression . Constant ( 0 ) ) ;
}
}
}
var customExpressionBuilder = new CustomExpressionBuilderWithoutValueTest ( ) ;
var options = new FlexFilterOptions < PeopleEntity > ( customExpressionBuilder ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;
var filter = new DataFilter
{
Logic = DataFilterLogic . And ,
Filters = new List < DataFilter >
{
new ( )
{
Field = "Age" ,
Operator = "Even" ,
Value = null
}
}
} ;
var result = flexFilter . FilterData ( _ctx . People , filter ) . ToList ( ) ; L'utilisation avec l'injection de dépendance peut ressembler à ceci (voir tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs , GenericFlexFilterWithExpressionBuilderUsage() Méthode):
class CustomExpressionBuilder : FilterExpressionBuilder < PeopleEntity > ;
class GenericFlexFilterService ( FlexFilter < PeopleEntity > flexFilter )
{
public FlexFilter < PeopleEntity > FlexFilter { get ; } = flexFilter ;
}
var serviceCollection = new ServiceCollection ( ) ;
serviceCollection . AddSingleton < FilterExpressionBuilder < PeopleEntity > , CustomExpressionBuilder > ( ) ;
serviceCollection . AddSingleton < FlexFilterOptions < PeopleEntity > > ( ) ;
serviceCollection . AddSingleton < FlexFilter < PeopleEntity > > ( ) ;
serviceCollection . AddTransient < GenericFlexFilterService > ( ) ;
var serviceProvider = serviceCollection . BuildServiceProvider ( ) ;
var testInstance = serviceProvider . GetRequiredService < GenericFlexFilterService > ( ) ; Ici, CustomExpressionBuilder est un constructeur d'expression de filtre personnalisé, qui est transmis au constructeur FlexFilterOptions. Ensuite, FlexFilterOptions est transmise au constructeur FlexFilter. Enfin, FlexFilter est injecté dans la classe GenericFlexFilterService .
Cela peut sembler un peu compliqué, mais c'est assez puissant. FlexFetcher est très flexible.
Dans des exemples précédents, nous avons utilisé des noms de champ tels qu'ils sont dans les entités, mais il est possible d'utiliser des noms de champ personnalisés. Il y a deux façons de le faire:
Le moyen le plus simple consiste à définir les alias de champ comme chaîne:
// Manual creation of FlexFilter
var addressFilterOptions = new FlexFilterOptions < AddressEntity > ( ) ;
addressFilterOptions . Field ( entity => entity . City ) . Map ( "Town" ) ;
FlexFilter < AddressEntity > addressFilter = new FlexFilter < AddressEntity > ( addressFilterOptions ) ;
// Dependency injection of FlexFetcher
Services . AddSingletonFlexOptions < FlexFetcherOptions < AddressEntity > > ( options =>
{
options . Field ( entity => entity . City ) . Map ( "Town" ) ;
} ) ;
Services . AddSingleton < FlexFetcher < AddressEntity > > ( ) ;Dans cet exemple, nous cartographient la propriété Addressity.City sur le terrain de "ville", c'est-à-dire que nous pouvons utiliser la "ville" dans les filtres et les trieurs au lieu de "ville".
La même chose peut être faite avec la propriété de la classe de modèle:
public class AddressModel
{
public string Town { get ; set ; }
}
// Manual creation of FlexFilter
var addressFilterOptions = new FlexFilterOptions < AddressEntity , AddressModel > ( ) ;
addressFilterOptions . Field ( entity => entity . City ) . Map ( model => model . Town ) ;
FlexFilter < AddressEntity , AddressModel > addressFilter = new FlexFilter < AddressEntity , AddressModel > ( addressFilterOptions ) ;
// Dependency injection of FlexFetcher
Services . AddSingletonFlexOptions < FlexFetcherOptions < AddressEntity , AddressModel > > ( options =>
{
options . Field ( entity => entity . City ) . Map ( model => model . Town ) ;
} ) ;
Services . AddSingleton < FlexFetcher < AddressEntity , AddressModel > > ( ) ;Dans cet exemple, nous cartographient la propriété Addressity.City pour adressmodel.town Property. En général, il offre la possibilité de cartographier des modèles de vue aux entités et d'avoir des mappages différents pour différents modèles de vue.
Plusieurs mappages sont autorisés, il est donc possible de cartographier un champ d'entité à plusieurs alias, par exemple:
options . Field ( entity => entity . City ) . Map ( "Town" ) . Map ( "CityName" ) ;
Il est autorisé à cartographier pour afficher les propriétés du modèle et les valeurs de chaîne en même temps:
options . Field ( x => x . City ) . Map ( model => model . Town ) . Map ( "CityName" ) ;
Le mappage des champs personnalisés (voir ci-dessous) est également autorisé:
var customField = new PeopleFullNameCustomField ( ) ; var options = new FlexSorterOptions < PeopleEntity > ( ) ; options . AddCustomField ( customField ) . Map ( "Title" ) ; var flexSorter = new FlexSorter < PeopleEntity > ( options ) ;
Dans des exemples précédents, nous avons utilisé uniquement les propriétés des entités, mais il est possible d'utiliser des champs personnalisés avec des expressions personnalisées.
Ils pourraient être utilisés dans Flexsorters, FlexFilters, FlexFetchers.
Disons que nous voulons ajouter un champ personnalisé "FullName" à la Sentialité:
public class PeopleFullNameCustomField : BaseFlexCustomField < PeopleEntity , string > // string is a type of field
{
public override string Field => "FullName" ;
protected override Expression < Func < PeopleEntity , string > > BuildFieldExpression ( IFlexFetcherContext ? context = null )
{
return p => p . Surname + " " + p . Name ;
}
}
// Manual creation of FlexSorter
var customField = new PeopleFullNameCustomField ( ) ;
var options = new FlexSorterOptions < PeopleEntity > ( ) ;
options . AddCustomField ( customField ) . Map ( "Title" ) ;
var flexSorter = new FlexSorter < PeopleEntity > ( options ) ;
// Dependency injection of FlexFetcher
Services . AddSingletonFlexOptions < FlexFetcherOptions < PeopleEntity > > ( options =>
{
options . AddCustomField ( new PeopleFullNameCustomField ( ) ) . Map ( "Title" ) ; // Map is optional
} ) ;
Services . AddSingleton < FlexFetcher < PeopleEntity > > ( ) ; Probablement, dans la plupart des cas, les champs personnalisés que nous avons vus dans la section précédente sont suffisants, mais il est parfois nécessaire d'avoir des champs personnalisés avec des expressions personnalisées dans des filtres pour une logique de filtre plus complexe.
Disons que nous voulons ajouter des «groupes populaires» de champ personnalisés à Peopleentity et y appliquer le filtre «AnyGroup»:
public class PeopleWithManyToManyGroupsCustomFilter : BaseFlexCustomFieldFilter < PeopleEntity >
{
public override string Field => "PeopleGroups" ;
protected override Expression < Func < PeopleEntity , bool > > BuildFilterExpression ( string filterOperator , object ? filterValue ,
IFlexFetcherContext ? context = null )
{
string value = ( string ) filterValue ! ;
return filterOperator switch
{
"AnyGroup" => p => p . PeopleGroups . Any ( pg => pg . Group ! . Name == value ) ,
_ => throw new NotSupportedException ( $ "Invalid filter operator: { filterOperator } " )
} ;
}
}
// Another way to create extended FlexFilter - custom class inherrited from FlexFilter
public class PeopleWithManyToManyGroups : FlexFilter < PeopleEntity >
{
public PeopleWithManyToManyGroups ( PeopleWithManyToManyGroupsCustomFilter customFilter )
{
Options . AddCustomField ( customFilter ) ;
}
}
var customFilter = new PeopleWithManyToManyGroupsCustomFilter ( ) ;
var peopleFilter = new PeopleWithManyToManyGroups ( customFilter ) ; Le contexte FlexFetcher est un objet spécial qui est passé aux champs personnalisés et aux filtres personnalisés.
Il peut contenir toutes les données nécessaires pour les champs personnalisés et les filtres personnalisés.
Disons que nous devons choisir différents domaines d'entités en fonction de la culture:
public class CustomContext : IFlexFetcherContext // Create your own context class
{
public CultureInfo Culture { get ; set ; } = null ! ;
}
public class PeopleOriginCountryCustomField : BaseFlexCustomField < PeopleEntity , string ? >
{
public override string Field => "Country" ;
protected override Expression < Func < PeopleEntity , string ? > > BuildFieldExpression ( IFlexFetcherContext ? context = null )
{
if ( context is not CustomContext customContext )
{
throw new NotSupportedException ( "Invalid context type" ) ;
}
if ( customContext . Culture . Name == "de-DE" )
{
return entity => entity . OriginCountryDe ;
}
return entity => entity . OriginCountryEn ;
}
}
var customExpressionFilter = new PeopleOriginCountryCustomField ( ) ;
var options = new FlexFilterOptions < PeopleEntity > ( ) ;
options . AddCustomField ( customExpressionFilter ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;
var filter = new DataFilter
{
Filters = new List < DataFilter >
{
new ( )
{
Field = "Country" ,
Operator = DataFilterOperator . Equal ,
Value = "Deutschland"
}
}
} ;
var context = new CustomContext
{
Culture = new CultureInfo ( "de-DE" )
} ;
var result = flexFilter . FilterData ( _ctx . People , filter , context ) . ToList ( ) ; Dans les sections précédentes, nous avons vu comment travailler avec les champs et comment les cartographier. Par défaut, tous les champs sont visibles et peuvent être utilisés dans les filtres et les trieurs. Mais dans certains cas, il faut masquer certains champs à être utilisés dans les filtres et les trieurs.
Il y a deux façons de cacher les champs:
La voie de définir le champ comme caché:
var options = new FlexFilterOptions < PeopleEntity > ( ) ;
options . Field ( x => x . CreatedByUserId ) . Hide ( ) ; // CreatedByUserId is a hidden field, it can't be used in filters and sorters
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;La façon de définir tous les champs d'entités comme cachés:
var options = new FlexFilterOptions < PeopleEntity > ( ) ;
options . HideOriginalFields ( ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;Les alias de champ ne sont pas affectés par la cachette, ils peuvent donc être utilisés dans les filtres et les trieurs même si les champs d'origine sont cachés.
Les champs personnalisés peuvent également être cachés:
class SimplePeopleSorterWithCustomSorter : FlexSorter < PeopleEntity >
{
public SimplePeopleSorterWithCustomSorter ( )
{
Options . AddCustomField ( new PeopleFullNameCustomField ( ) ) . Map ( "Title" ) . Hide ( ) ;
}
}Les champs personnalisés ne sont pas cachés automatiquement lorsque HideoriginalFields () est utilisé, ils doivent donc être cachés manuellement si nécessaire.
FlexFetcher est conçu pour être utilisé dans la communication machine à machine, il est donc important de pouvoir sérialiser et désérialiser les requêtes.
Dans les cas simples, tout sérialiseur JSON peut être utilisé, mais en tant que SOOS, vous devez utiliser des champs de type de temps ou vous devez sérialiser / désérialiser les tableaux à utiliser In l'opérateur, vous devez appliquer des paramètres et des convertisseurs JSON personnalisés à partir de FlexFetcher.Serialization.NewtonsoftJson ou FlexFetcher.Serialization.SystemTextJson Packages.
Installez FlexFetcher.Serialization.NewtonsoftJson et obtenez les paramètres de la classe d'aide:
var jsonSettings = NewtonsoftHelper . GetSerializerSettings ( ) ;
var json = JsonConvert . SerializeObject ( filter , jsonSettings ) ;
var deserializedFilter = JsonConvert . DeserializeObject < DataFilter > ( json , jsonSettings ) ; Installez FlexFetcher.Serialization.SystemTextJson Package et obtenez les paramètres de la classe d'aide:
var jsonSettings = SystemTextJsonHelper . GetSerializerOptions ( ) ;
var json = JsonSerializer . Serialize ( filter , jsonSettings ) ;
var deserializedFilter = JsonSerializer . Deserialize < DataFilter > ( json , jsonSettings ) ;Il existe également des convertisseurs JSON qui permettent de sérialiser / désérialiser des objets vers / de JSON dans un format succinct comme celui-ci (exemple de DataFilter):
{
"L" : " And " ,
"Fs" : [
{
"O" : " Eq " ,
"F" : " Address.Town " ,
"V" : " New York "
}
]
} Voir plus d'exemples de format succinct dans tests/FlexFetcherTests/SerializationTests/NewtonsoftTests.cs et tests/FlexFetcherTests/SerializationTests/SystemTextJsonTests.cs et également dans des exemples de projets samples/WebApiSample et samples/WebApiSample.Framework48 .
Pour prendre en charge le format succinct, il est nécessaire d'utiliser les prochains convertisseurs de FlexFetcher.Serialization.NewtonsoftJson et FlexFetcher.Serialization.SystemTextJson en conséquence:
FlexFetcherDataSorterConverterFlexFetcherDataSortersConverterFlexFetcherDataPagerConverterFlexFetcherDataFilterConverterFlexFetcherDataQueryConverter Tous les convertisseurs ont un paramètre de constructeur readOnlyShortForm . S'il est réglé sur true, seul le format succinct sera autorisé pour la désérialisation. Sinon, les formats à la fois complets et succincts seront autorisés.
En général, il n'est pas nécessaire d'utiliser readOnlyShortForm dans la plupart des cas, mais si vous souhaitez restreindre la désérialisation au format succinct uniquement, vous pouvez le définir sur true.
FlexFetcher peut être utilisé dans les projets ASP.NET, à la fois le noyau et le framework, mais la configuration des sérialiseurs est différente.
Des étapes suivantes sont nécessaires pour configurer la sérialisation dans ASP.NET Core Projects (exemple pour System.Text.json):
FlexFetcherModelBinderFlexFetcherModelBinderProviderAddControllers dans Program.cs comme ceci: builder . Services . AddControllers ( options =>
{
options . ModelBinderProviders . Insert ( 0 , new FlexFetcherModelBinderProvider ( ) ) ;
} )
. AddJsonOptions ( options =>
{
options . JsonSerializerOptions . Converters . Add ( new GenericConverter ( ) ) ;
// Next converters are optional, but they are needed to support succinct format
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataSorterConverter ( ) ) ;
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataSortersConverter ( ) ) ;
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataPagerConverter ( ) ) ;
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataFilterConverter ( ) ) ;
options . JsonSerializerOptions . Converters . Add ( new FlexFetcherDataQueryConverter ( ) ) ;
} ) ; Voir code dans samples/WebApiSample .
Des étapes suivantes sont nécessaires pour configurer la sérialisation dans les projets ASP.NET Framework (exemple pour newtonsoft.json):
FlexFetcherModelBinderFlexFetcherModelBinderProviderWebApiConfig.cs comme ceci: var jsonSettings = NewtonsoftHelper . GetSerializerSettings ( ) ;
config . Formatters . JsonFormatter . SerializerSettings = jsonSettings ;
// Next converters are optional, but they are needed to support succinct format
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataFilterConverter ( ) ) ;
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataSortersConverter ( ) ) ;
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataSorterConverter ( ) ) ;
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataPagerConverter ( ) ) ;
config . Formatters . JsonFormatter . SerializerSettings . Converters . Add ( new FlexFetcherDataQueryConverter ( ) ) ;
config . Services . Insert ( typeof ( ModelBinderProvider ) , 0 , new FlexFetcherModelBinderProvider ( ) ) ; Voir code dans samples/WebApiSample.Framework48 .
Il y a deux exemples de projets dans le référentiel:
samples/WebApiSample - ASP.net Core Web Projectsamples/WebApiSample.Framework48 - ASP.NET Framework 4.8 Projet API WebLes deux projets ont les mêmes fonctionnalités et montrent comment utiliser FlexFetcher dans les projets ASP.NET.
Construisez et exécutez-les pour voir comment FlexFetcher fonctionne dans de vrais projets. Utilisez votre client REST préféré pour envoyer des demandes à l'API. Des exemples de demandes peuvent être trouvés dans samples/WebApiSample/ReadMe.md et samples/WebApiSample.Framework48/ReadMe.md .
Il existe également des tests dans le dossier tests/FlexFetcherTests qui montrent comment utiliser FlexFetcher dans différents scénarios.