Flexfetcher ist eine .NET -Bibliothek zum Filtern, Sortieren und Paging -Daten. Es wurde auf OOP -Prinzipien entwickelt und kann in jedem .NET -Projekt verwendet werden: Web, Desktop, Mobile usw. Flexfetcher ist vom Format Telerik Kendo UI Grid -Objekte inspiriert.
Es gibt viele großartige Bibliotheken zum Filtern, Sortieren, Paging -Daten in .NET: Sieb, Querykit, LightQuery usw. Aber die meisten von ihnen sind nicht auf der Grundlage von OOP -Prinzipien konzipiert. Sie haben Abfragesyntaxen, die als menschlich lesbar gedacht sind (alle Beispiele stammen aus diesen Bibliothekendokumentation):
sorts=LikeCount,CommentCount,-created&filters=LikeCount>10,Title@=awesome title,&page=1&pageSize=10
oder
""(Age ^^ [20, 30, 40]) && (BirthMonth ^^* ["January", "February", "March"]) || (Id ^^ ["6d623e92-d2cf-4496-a2df-f49fa77328ee"])""
oder
`?sort=country&thenSort=email desc`
Aber gleichzeitig:
Flexfetcher ist nicht besser oder schlechter als diese Bibliotheken, es ist einfach anders. Es akzeptiert Abfragen in einem Format von Objekten, das nach/von JSON wie folgt serialisiert/deserialisiert werden kann:
?Filters={"Logic":"And","Filters":[{"Operator":"Eq","Field":"Address.Town","Value":"New York"}]}
Oder, wenn Sie mehr kompaktes Format bevorzugen, auch so:
?Filter={"L":"And","Fs":[{"O":"Eq","F":"Address.Town","V":"New York"}]}
Oder wenn Sie eine Postanforderung (RPC -Stil) verwenden möchten, genau wie diese:
{
"Filters" : {
"Logic" : " and " ,
"Filters" : [
{
"Operator" : " eq " ,
"Field" : " Address.Town " ,
"Value" : " New York "
}
]
}
}Dieses Format ist für den Menschen leicht zu lesen und zu verstehen, leicht zu erweitern, leicht zu serialisieren/deserialisieren und in der Kommunikation von Maschinen zu Maschinen einfach zu bedienen ist.
Flexfetcher ist für die nächsten Plattformen erstellt:
Dies bedeutet, dass Sie es sowohl in .NET Core (siehe samples/WebApiSample ) als auch in .NET Framework (siehe samples/WebApiSample.Framework48 ) -Projekte verwenden können.
Flexfetcher unterstützt die nächsten Datentypen für Felder, die in Filtern und Sortierern verwendet werden:
Alle Werte können nullbar sein.
Sie können Flexfetcher (Nuget) über Nuget Package Manager -Konsole installieren, indem Sie den nächsten Befehl ausführen:
dotnet add package FlexFetcher
So installieren Sie flexfetcher.dependencyInjunction.microsoft (Nuget):
dotnet add package FlexFetcher.DependencyInjection.Microsoft
So installieren Sie Flexfetcher.Serialization.newtonsoftjson (Nuget):
dotnet add package FlexFetcher.Serialization.NewtonsoftJson
So installieren Sie Flexfetcher.Serialization.Systemtextjson (Nuget):
dotnet add package FlexFetcher.Serialization.SystemTextJson
Alle Beispiele werden im Testdatensatz durchgeführt, der in
tests/TestData/InMemoryDataHelper.csdefiniert ist und austests/TestData/Database/PeopleEntity.csundtests/TestData/Database/AddressEntity.csenthält.
Der einfachste Weg, um Flexfetcher zu verwenden, besteht darin, Erweiterungsmethoden für IQueryable<T> und IEnumerable<T> -Knaszierungen zu verwenden.
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 ( ) ; Erweiterungsmethoden sind gut für einfache Fälle, aber ihre Verwendung ist sehr begrenzt.
Für komplexere Fälle können Sie FlexFetcher -Klassen verwenden: FlexFilter<TEntity> und FlexFilter<TEntity, TModel> , FlexSorter<TEntity> und FlexSorter<TEntity, TModel> , FlexFetcher<TEntity> FlexPager<TEntity> Flexpager < FlexPager<TEntity, TModel> FlexFetcher<TEntity, TModel> .
Auch wenn dies nicht empfohlen wird, aber aus Gründen der Klarheit sehen wir sehen, wie man Instanzen von Klassen manuell erstellt. Wir werden die Abhängigkeitsinjektion im entsprechenden Abschnitt später untersuchen.
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 Vergessen Sie nicht, FlexFetcher.DependencyInjection.Microsoft mit Abhängigkeitsinjektion zu verwenden.
Es ist möglich, die Hauptklasse der Flexfetcher sowie der Komponenten zu injizieren: Flexfilter, FlexSorter, Flexpager. Die grundlegende Verwendung ist:
services . AddSingleton < FlexFetcher < PeopleEntity > > ( ) ;Flexfetcher -Klassen haben keinen Zustand, daher ist es sicher, sie als Singletons zu verwenden. Aber wenn Sie sie als Scoped oder Transient verwenden möchten, liegt es an Ihnen.
Fortgeschrittene szenarische Füllung werden als nächstes gezeigt. Weitere Beispiele finden Sie in tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs , samples/WebApiSample samples/WebApiSample.Framework48 .
In unserem Beispieldatenmodell haben wir verschachtelte Objekte: Peopleentity hat eine Adresseigenschaft. Mal sehen, wie man durch verschachteltes Objekt filtert:
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 ( ) ;Das Gleiche kann mit Abhängigkeitsinjektion erfolgen:
Services . AddSingleton < FlexFilter < AddressEntity > > ( ) ;
Services . AddSingletonFlexOptions < FlexFilterOptions < PeopleEntity > > ( ( provider , options ) =>
{
options . AddNestedFlexFilter ( provider . GetRequiredService < FlexFilter < AddressEntity > > ( ) ) ;
} ) ;
Services . AddSingleton < FlexFilter < PeopleEntity > > ( ) ;Das gleiche Prinzip kann auf FlexSorter, Flexpager und Flexfetcher angewendet werden.
Weitere Beispiele in tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs und samples/WebApiSample .
In früheren Beispielen haben wir nur einen Filter verwendet, aber es ist möglich, mehrere Filter mit oder oder Logiken wie folgt zu verwenden:
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 unterstützt verschachtelte Filter mit jeder Tiefe.
Wenn keine Logik angegeben ist, wird sie standardmäßig auf und standardmäßig festgelegt.
Der Filter kann entweder (Filter und Logik) oder (Feld-, Bediener- und Wert-) Eigenschaften enthalten, jedoch nicht beides.
Wir haben bereits Beispiele mit gleichen, größeren Betreibern gesehen, aber es gibt mehr Betreiber:
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 } } Um einen eigenen Filterbetreiber zu erstellen, wird es benötigt:
BaseFilterExpressionHandler erbelt wurdeFilterExpressionBuilder erbelt wurdeAddCustomExpressionHandlers in der benutzerdefinierten FilterexpressionBuilder -Klasse Es könnte so aussehen (siehe 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 ( ) ;Es ist auch möglich, einen benutzerdefinierten Filterbetreiber zu erstellen, der überhaupt einen Wert benötigt:
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 ( ) ; Die Verwendung mit Abhängigkeitsinjektion könnte so aussehen (siehe tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs , GenericFlexFilterWithExpressionBuilderUsage() Methode):
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 > ( ) ; Hier ist CustomExpressionBuilder ein Builder für benutzerdefinierte Filterausdruck, der an den Flexfilteroptions -Konstruktor übergeben wird. Dann werden Flexfilteroptionen an den Flexfilter -Konstruktor übergeben. Schließlich wird Flexfilter in die GenericFlexFilterService -Klasse injiziert.
Es mag ein bisschen kompliziert erscheinen, aber es ist ziemlich mächtig. Flexfetcher ist sehr flexibel.
In früheren Beispielen haben wir Feldnamen als in Entitäten verwendet, aber es ist möglich, benutzerdefinierte Feldnamen zu verwenden. Es gibt zwei Möglichkeiten, dies zu tun:
Der einfachste Weg ist, Feldalias als Zeichenfolge zu definieren:
// 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 > > ( ) ;In diesem Beispiel kartieren wir Adresentität.City -Eigentum in "Stadt", dh wir können "Stadt" in Filtern und Sortierern anstelle von "Stadt" verwenden.
Gleiches gilt für die Eigenschaft der Modellklasse:
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 > > ( ) ;In diesem Beispiel kartieren wir die Eigenschaft von AdressENTITY.City an die Eigenschaft von Model.town. Im Allgemeinen bietet es Möglichkeit, Ansichtsmodelle an Unternehmen abzubilden und unterschiedliche Zuordnungen für verschiedene Ansichtsmodelle zu haben.
Mehrere Zuordnungen sind erlaubt, daher ist es möglich, ein Entitätsfeld mehrerer Aliase zuzuordnen, beispielsweise:
options . Field ( entity => entity . City ) . Map ( "Town" ) . Map ( "CityName" ) ;
Es darf die Zuordnung von Modelleigenschaften und gleichzeitig Stringwerten zuordnen:
options . Field ( x => x . City ) . Map ( model => model . Town ) . Map ( "CityName" ) ;
Die Zuordnung zu benutzerdefinierten Feldern (siehe unten) ist ebenfalls zulässig:
var customField = new PeopleFullNameCustomField ( ) ; var options = new FlexSorterOptions < PeopleEntity > ( ) ; options . AddCustomField ( customField ) . Map ( "Title" ) ; var flexSorter = new FlexSorter < PeopleEntity > ( options ) ;
In früheren Beispielen haben wir nur Eigenschaften von Entitäten verwendet, aber es ist möglich, benutzerdefinierte Felder mit benutzerdefinierten Ausdrücken zu verwenden.
Sie können in Flexsortern, Flexfiltern und Flexfetchern verwendet werden.
Nehmen wir an, wir möchten Peopleentity ein benutzerdefiniertes Feld "Fullname" hinzufügen:
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 > > ( ) ; Wahrscheinlich reichen in den meisten Fällen benutzerdefinierte Felder, die wir im vorherigen Abschnitt gesehen haben, aus, aber manchmal benötigt es, um benutzerdefinierte Felder mit benutzerdefinierten Ausdrücken in Filtern für komplexere Filterlogik zu haben.
Nehmen wir an, wir möchten Peopleentity "Peoplegroups" in ein benutzerdefiniertes Feld hinzufügen und "Anygroup" -Filter anwenden:
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 ) ; Flexfetcher Context ist ein spezielles Objekt, das an benutzerdefinierte Felder und benutzerdefinierte Filter übergeben wird.
Es kann alle Daten enthalten, die für benutzerdefinierte Felder und benutzerdefinierte Filter benötigt werden.
Angenommen, wir müssen je nach Kultur verschiedene Unternehmensfelder auswählen:
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 ( ) ; In früheren Abschnitten haben wir gesehen, wie man mit Feldern arbeitet und wie man sie zuordnet. Standardmäßig sind alle Felder sichtbar und können in Filtern und Sortierern verwendet werden. In einigen Fällen ist es jedoch erforderlich, um einige Felder vor Filtern und Sortierern zu verbergen.
Es gibt zwei Möglichkeiten, Felder zu verbergen:
Der Weg, das Feld als versteckt zu definieren:
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 ) ;Der Weg, alle Entitätsfelder als versteckt zu definieren:
var options = new FlexFilterOptions < PeopleEntity > ( ) ;
options . HideOriginalFields ( ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;Feld Aliase sind nicht durch Versteck betroffen, sodass sie in Filtern und Sortierern verwendet werden können, selbst wenn die ursprünglichen Felder verborgen sind.
Benutzerdefinierte Felder sind ebenfalls versteckt:
class SimplePeopleSorterWithCustomSorter : FlexSorter < PeopleEntity >
{
public SimplePeopleSorterWithCustomSorter ( )
{
Options . AddCustomField ( new PeopleFullNameCustomField ( ) ) . Map ( "Title" ) . Hide ( ) ;
}
}Benutzerdefinierte Felder werden nicht automatisch versteckt, wenn Hideoriginalfields () verwendet wird, sodass sie bei Bedarf manuell versteckt werden sollten.
Flexfetcher ist so konzipiert, dass sie für die Kommunikation von Maschinen zu Maschinen verwendet werden können. Daher ist es wichtig, Abfragen zu serialisieren und zu deserialisieren.
In den einfachen Fällen kann ein JSON -Serializer verwendet werden, aber so wie Sie wie Sie Felder mit dem timeOnly -Typ verwenden müssen, oder Sie müssen Arrays serialisieren/deserialisieren, um In Bediener Einstellungen und kundenspezifische JSON -Konverter von FlexFetcher.Serialization.NewtonsoftJson oder FlexFetcher.Serialization.SystemTextJson zu verwenden.
Installieren Sie FlexFetcher.Serialization.NewtonsoftJson -Paket und erhalten Sie Einstellungen von der Helferklasse:
var jsonSettings = NewtonsoftHelper . GetSerializerSettings ( ) ;
var json = JsonConvert . SerializeObject ( filter , jsonSettings ) ;
var deserializedFilter = JsonConvert . DeserializeObject < DataFilter > ( json , jsonSettings ) ; Installieren Sie FlexFetcher.Serialization.SystemTextJson -Paket und erhalten Sie Einstellungen aus der Helferklasse:
var jsonSettings = SystemTextJsonHelper . GetSerializerOptions ( ) ;
var json = JsonSerializer . Serialize ( filter , jsonSettings ) ;
var deserializedFilter = JsonSerializer . Deserialize < DataFilter > ( json , jsonSettings ) ;Es gibt auch JSON -Konverter, die es ermöglichen, Objekte nach/von JSON in einem solchen Format wie diesem zu serialisieren/zu deserialisieren (DataFilter -Beispiel):
{
"L" : " And " ,
"Fs" : [
{
"O" : " Eq " ,
"F" : " Address.Town " ,
"V" : " New York "
}
]
} Weitere Beispiele für das prägnante Format in tests/FlexFetcherTests/SerializationTests/NewtonsoftTests.cs und tests/FlexFetcherTests/SerializationTests/SystemTextJsonTests.cs sowie in Beispielprojekten samples/WebApiSample und samples/WebApiSample.Framework48 .
Um das prägnante Format zu unterstützen, benötigt es, um nächste Konverter von FlexFetcher.Serialization.NewtonsoftJson und FlexFetcher.Serialization.SystemTextJson entsprechend:
FlexFetcherDataSorterConverterFlexFetcherDataSortersConverterFlexFetcherDataPagerConverterFlexFetcherDataFilterConverterFlexFetcherDataQueryConverter Alle Konverter haben den Konstruktorparameter readOnlyShortForm . Wenn es auf wahr ist, dürfte nur ein kurzes Format für die Deserialisierung zulässig sein. Andernfalls werden sowohl vollständige als auch prägnante Formate erlaubt.
Im Allgemeinen müssen in den meisten Fällen keine readOnlyShortForm verwendet werden. Wenn Sie jedoch die Deserialisierung nur auf das prägnante Format einschränken möchten, können Sie es auf wahr einstellen.
Flexfetcher kann in ASP.NET -Projekten sowohl Kern- als auch Framework verwendet werden, aber die Konfiguration der Serializer ist unterschiedlich.
Die nächsten Schritte sind erforderlich, um die Serialisierung in ASP.NET -Kernprojekten zu konfigurieren (Beispiel für System.text.json):
FlexFetcherModelBinderFlexFetcherModelBinderProviderAddControllers -Methode in Program.cs wie folgt: 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 ( ) ) ;
} ) ; Siehe Code in samples/WebApiSample .
Die nächsten Schritte sind erforderlich, um die Serialisierung in ASP.NET -Framework -Projekten zu konfigurieren (Beispiel für newtonsoft.json):
FlexFetcherModelBinderFlexFetcherModelBinderProviderWebApiConfig.cs wie folgt: 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 ( ) ) ; Siehe Code in samples/WebApiSample.Framework48 .
Es gibt zwei Beispielprojekte im Repository:
samples/WebApiSample - ASP.NET Core Web API -Projektsamples/WebApiSample.Framework48 - ASP.NET Framework 4.8 Web API -ProjektBeide Projekte haben die gleiche Funktionalität und zeigen, wie Flexfetcher in ASP.NET -Projekten verwendet werden.
Erstellen Sie sie einfach und führen Sie sie aus, um zu sehen, wie Flexfetcher in realen Projekten funktioniert. Verwenden Sie Ihren bevorzugten REST -Client, um Anfragen an die API zu senden. Beispiele für Anfragen finden Sie in samples/WebApiSample/ReadMe.md und samples/WebApiSample.Framework48/ReadMe.md .
Außerdem gibt es Tests in tests/FlexFetcherTests -Ordner, die zeigen, wie Flexfetcher in verschiedenen Szenarien verwendet werden.