Flexfetcher - это библиотека .NET для фильтрации, сортировки, датчиков под пейджингом. Он разработан на основе принципов ООП и может использоваться в любом проекте .NET: Web, Desktop, Mobile и т. Д. Flexfetcher вдохновляется форматом объектов UB -интерфейса Telerik Kendo.
Существует много отличных библиотек для фильтрации, сортировки, данных подкисления в .net: Sieve, Querykit, Lightquery и т. Д., Но большинство из них не разработаны на основе принципов ООП. У них есть синтаксисы запросов, которые предназначены для того, чтобы быть читаемыми человеком, как (все примеры взяты из этой документации библиотек):
sorts=LikeCount,CommentCount,-created&filters=LikeCount>10,Title@=awesome title,&page=1&pageSize=10
или
""(Age ^^ [20, 30, 40]) && (BirthMonth ^^* ["January", "February", "March"]) || (Id ^^ ["6d623e92-d2cf-4496-a2df-f49fa77328ee"])""
или
`?sort=country&thenSort=email desc`
Но в то же время:
Flexfetcher не лучше или хуже, чем эти библиотеки, это просто по -другому. Он принимает запросы в формате объектов, которые могут быть сериализованы/десериализованы на/от JSON, как это:
?Filters={"Logic":"And","Filters":[{"Operator":"Eq","Field":"Address.Town","Value":"New York"}]}
Или, если вы предпочитаете более компактный формат, даже нравится это:
?Filter={"L":"And","Fs":[{"O":"Eq","F":"Address.Town","V":"New York"}]}
Или, если вы хотите использовать Post запрос (стиль RPC), точно так же:
{
"Filters" : {
"Logic" : " and " ,
"Filters" : [
{
"Operator" : " eq " ,
"Field" : " Address.Town " ,
"Value" : " New York "
}
]
}
}Этот формат легко читать и понимать для людей, простых в продлении, простых в сериализации/десериализме и простых в использовании в связи с машиной к машине.
Flexfetcher - это строительство для следующих платформ:
Это означает, что вы можете использовать его как в .NET Core (см. samples/WebApiSample ) и .NET Framework (см. Проекты samples/WebApiSample.Framework48 ).
Flexfetcher поддерживает следующие типы данных для полей, которые используются в фильтрах и сортировщиках:
Все значения могут быть нулевыми.
Вы можете установить glexfetcher (nuget) через консоль Manager Package Nuget, выполнив следующую команду:
dotnet add package FlexFetcher
Чтобы установить glexfetcher.dependencyInction.microsoft (nuget):
dotnet add package FlexFetcher.DependencyInjection.Microsoft
Чтобы установить glexfetcher.serialization.newtonsoftjson (nuget):
dotnet add package FlexFetcher.Serialization.NewtonsoftJson
Чтобы установить glexfetcher.serialization.systemtextjson (nuget):
dotnet add package FlexFetcher.Serialization.SystemTextJson
Все примеры выполняются в тестовом наборе данных, который определяется в
tests/TestData/InMemoryDataHelper.csи состоит изtests/TestData/Database/PeopleEntity.csиtests/TestData/Database/AddressEntity.cs.
Самый простой способ использования Flexfetcher - это использовать методы расширения для IQueryable<T> и 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 ( ) ; Методы расширений хороши для простых случаев, но их использование очень ограничено.
Для более сложных случаев вы можете использовать классы FlexFetcher : FlexFilter<TEntity> и FlexFilter<TEntity, TModel> , FlexSorter<TEntity> и FlexSorter<TEntity, TModel> , FlexPager<TEntity> и FlexPager<TEntity, TModel> , FlexFetcher<TEntity> и FlexFetcher<TEntity, TModel> .
Несмотря на то, что это не рекомендуется, но для ясности, давайте посмотрим, как создать экземпляры классов вручную. Позже рассмотрим инъекцию зависимостей в соответствующем разделе.
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 Чтобы использовать Flexfetcher с впрыском зависимостей, не забудьте установить FlexFetcher.DependencyInjection.Microsoft .
Можно ввести основной класс Flexfetcher, а также его компоненты: Flexfilter, Flexsorter, Flexpager. Основное использование:
services . AddSingleton < FlexFetcher < PeopleEntity > > ( ) ;У классов Flexfetcher нет ни одного состояния, поэтому безопасно использовать их в качестве синглтонов. Но если вы хотите использовать их в качестве прицела или переходного, это зависит от вас.
Более продвинутая сценария будет показана дальше. Также см. Больше примеров в tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs , samples/WebApiSample ) и samples/WebApiSample.Framework48 .
В нашей примере модели данных у нас есть вложенные объекты: у людей есть адрес собственности. Посмотрим, как фильтровать по вложенному объекту:
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 ( ) ;То же самое можно сделать с инъекцией зависимости:
Services . AddSingleton < FlexFilter < AddressEntity > > ( ) ;
Services . AddSingletonFlexOptions < FlexFilterOptions < PeopleEntity > > ( ( provider , options ) =>
{
options . AddNestedFlexFilter ( provider . GetRequiredService < FlexFilter < AddressEntity > > ( ) ) ;
} ) ;
Services . AddSingleton < FlexFilter < PeopleEntity > > ( ) ;Тот же принцип может быть применен к Flexsorter, Flexpager и Flexfetcher.
См. Больше примеров в tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs и samples/WebApiSample .
В предыдущих примерах мы использовали только один фильтр, но можно использовать несколько фильтров с или или логики, как это:
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 поддерживает вложенные фильтры с любой глубиной.
Если логика не указана, она будет установлена по умолчанию.
Фильтр может содержать свойства (фильтры и логика) или (полевые, операторы и значение), но не оба.
Мы уже видели примеры с равными, большими операторами, но есть больше операторов:
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 } } Чтобы создать собственного оператора фильтра, это необходимо:
BaseFilterExpressionHandlerFilterExpressionBuilderAddCustomExpressionHandlers в пользовательском фильме FilterExpressionBuilder Это может выглядеть так (см. 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 ( ) ;Также можно создать пользовательский оператор фильтра, который вообще нуждается в значении:
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 ( ) ; Использование с инъекцией зависимостей может выглядеть так (см. tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs , GenericFlexFilterWithExpressionBuilderUsage() Метод): Метод): Метод): Метод):
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 > ( ) ; Здесь CustomExpressionBuilder - это пользовательский строитель выражения фильтра, который передается конструктору Flexfilteroptions. Затем Flexfilteroptions передается в конструктор Flexfilter. Наконец, Flexfilter вводится в класс GenericFlexFilterService .
Это может показаться немного сложным, но это довольно мощно. Flexfetcher очень гибкий.
В предыдущих примерах мы использовали имена поля, как они находятся в объектах, но можно использовать пользовательские имена поля. Есть два способа сделать это:
Самый простой способ - определить псевдоним поле как строка:
// 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 > > ( ) ;В этом примере мы сопоставляем addressentity.city собственность в поле «город», то есть мы можем использовать «город» в фильтрах и сортировщиках вместо «города».
То же самое можно сделать со свойством модельного класса:
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 > > ( ) ;В этом примере мы сопоставляем свойство addressentity.city по адресу addrymodel.town. В целом он дает возможность отображать модели представления на сущности и иметь разные отображения для различных моделей представления.
Разрешено несколько отображений, поэтому можно сопоставить одно поле сущности с несколькими псевдонизами, например:
options . Field ( entity => entity . City ) . Map ( "Town" ) . Map ( "CityName" ) ;
Разрешено карту для просмотра свойств модели и одновременно для строковых значений:
options . Field ( x => x . City ) . Map ( model => model . Town ) . Map ( "CityName" ) ;
Картирование по пользовательским полям (см. Ниже) также разрешено:
var customField = new PeopleFullNameCustomField ( ) ; var options = new FlexSorterOptions < PeopleEntity > ( ) ; options . AddCustomField ( customField ) . Map ( "Title" ) ; var flexSorter = new FlexSorter < PeopleEntity > ( options ) ;
В предыдущих примерах мы использовали только свойства объектов, но можно использовать пользовательские поля с пользовательскими выражениями.
Они могут использоваться в Flexsorters, Flexfilters, Flexfetchers.
Допустим, мы хотим добавить пользовательское поле «полное имя» к людям:
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 > > ( ) ; Вероятно, в большинстве случаев пользовательских полей, которые мы видели в предыдущем разделе, достаточно, но иногда необходимо иметь пользовательские поля с пользовательскими выражениями в фильтрах для более сложной логики фильтра.
Допустим, мы хотим добавить настраиваемое поле «PeopleGroups» к людям и применить к нему фильтр «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 ) ; Контекст Flexfetcher - это специальный объект, который передается на пользовательские поля и пользовательские фильтры.
Он может содержать любые данные, которые необходимы для пользовательских полей и пользовательских фильтров.
Допустим, нам нужно выбрать разные объекты в зависимости от культуры:
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 ( ) ; В предыдущих разделах мы видели, как работать с областями и как их на карту. По умолчанию все поля видны и могут использоваться в фильтрах и сортировщиках. Но в некоторых случаях необходимо спрятать некоторые поля от использования в фильтрах и сортировщиках.
Есть два способа скрыть поля:
Способ определить поле как скрытое:
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 ) ;Способ определить все поля сущности как скрытые:
var options = new FlexFilterOptions < PeopleEntity > ( ) ;
options . HideOriginalFields ( ) ;
var flexFilter = new FlexFilter < PeopleEntity > ( options ) ;Полевые псевдонимы не подвержены укрытию, поэтому их можно использовать в фильтрах и сортировщиках, даже если исходные поля скрыты.
Пользовательские поля также могут быть скрыты:
class SimplePeopleSorterWithCustomSorter : FlexSorter < PeopleEntity >
{
public SimplePeopleSorterWithCustomSorter ( )
{
Options . AddCustomField ( new PeopleFullNameCustomField ( ) ) . Map ( "Title" ) . Hide ( ) ;
}
}Пользовательские поля не скрываются автоматически, когда используется hodooriginalfields (), чтобы они должны быть скрыты вручную, если это необходимо.
Flexfetcher предназначен для использования в связи с машиной и машиной, поэтому важно иметь возможность сериализовать и десериализовать запросы.
В простых случаях можно использовать любой сериализатор JSON, но, как вам нужно использовать поля с по времени, или вам необходимо сериализовать/десериализовать массивы для использования In операторе, вам необходимо применить настройки и пользовательские конвертеры JSON от FlexFetcher.Serialization.NewtonsoftJson или Flexfetcher.serialization.systemtemtemtemtemtemtemtemtemtember.serialization.newtonsoftjson или Flexfetcher.serialization.systemtemtemtemtemtemtemtemtemtember.serialization.newtonsoftjson или FlexFetcher.Serialization.SystemTextJson .
Установите FlexFetcher.Serialization.NewtonsoftJson и получить настройки от Helper Class:
var jsonSettings = NewtonsoftHelper . GetSerializerSettings ( ) ;
var json = JsonConvert . SerializeObject ( filter , jsonSettings ) ;
var deserializedFilter = JsonConvert . DeserializeObject < DataFilter > ( json , jsonSettings ) ; Установите FlexFetcher.Serialization.SystemTextJson и получает параметры из Helper Class:
var jsonSettings = SystemTextJsonHelper . GetSerializerOptions ( ) ;
var json = JsonSerializer . Serialize ( filter , jsonSettings ) ;
var deserializedFilter = JsonSerializer . Deserialize < DataFilter > ( json , jsonSettings ) ;Существуют также конвертеры JSON, которые позволяют сериализовать/десериализовать объекты в/из JSON в формате краткого формата (пример DataFilter):
{
"L" : " And " ,
"Fs" : [
{
"O" : " Eq " ,
"F" : " Address.Town " ,
"V" : " New York "
}
]
} См. Больше примеров краткого формата в tests/FlexFetcherTests/SerializationTests/NewtonsoftTests.cs и tests/FlexFetcherTests/SerializationTests/SystemTextJsonTests.cs , а также в samples/WebApiSample и samples/WebApiSample.Framework48 .
Для поддержки краткого формата необходимо использовать следующие конвертеры от FlexFetcher.Serialization.NewtonsoftJson и FlexFetcher.Serialization.SystemTextJson Соответственно:
FlexFetcherDataSorterConverterFlexFetcherDataSortersConverterFlexFetcherDataPagerConverterFlexFetcherDataFilterConverterFlexFetcherDataQueryConverter Все преобразователи имеют параметр конструктора readOnlyShortForm . Если он настроен на True, то будет разрешен только лакократный формат для дезиализации. В противном случае будут разрешены как полные, так и лаконичные форматы.
В целом, в большинстве случаев нет необходимости использовать readOnlyShortForm , но если вы хотите ограничить десериализацию только в лаконичном формате, вы можете установить ее на True.
Flexfetcher может использоваться в проектах ASP.NET, как в основном, так и в рамках, но конфигурация сериализаторов отличается.
Следующие шаги необходимы для настройки сериализации в основных проектах ASP.NET (пример для system.text.json):
FlexFetcherModelBinderFlexFetcherModelBinderProviderAddControllers в Program.cs . 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 ( ) ) ;
} ) ; См. Код в samples/WebApiSample .
Следующие шаги необходимы для настройки сериализации в проектах ASP.NET Framework (пример для Newtonsoft.json):
FlexFetcherModelBinderFlexFetcherModelBinderProviderWebApiConfig.cs 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 ( ) ) ; См. Код в samples/WebApiSample.Framework48 .
В репозитории есть два образца проекта:
samples/WebApiSample - ASP.net Core Web API Projectsamples/WebApiSample.Framework48 - ASP.NET Framework 4.8 Web API ProjectОба проекта имеют одинаковую функциональность и демонстрируют, как использовать Flexfetcher в проектах ASP.NET.
Просто создайте и запустите их, чтобы увидеть, как работает Flexfetcher в реальных проектах. Используйте свой любимый клиент REST для отправки запросов в API. Примеры запросов можно найти в samples/WebApiSample/ReadMe.md и samples/WebApiSample.Framework48/ReadMe.md .
Также в папке tests/FlexFetcherTests есть тесты, которые демонстрируют, как использовать Flexfetcher в разных сценариях.