FlexFetcher是一个.NET库,用于过滤,分类,分页数据。它是基于OOP原理设计的,可用于任何.NET项目:Web,桌面,移动设备等。FlexFetcher的灵感来自Telerik Kendo UI网格对象格式。
.NET中有很多很棒的库,用于过滤,分类,分页数据:筛,QueryKit,Lightquery等。但是,其中大多数不是基于OOP原理设计的。它们具有旨在可读的查询语法,例如(所有示例均来自这些库文档):
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/从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"}]}
或者,如果您想使用发布请求(RPC样式),则像这样:
{
"Filters" : {
"Logic" : " and " ,
"Filters" : [
{
"Operator" : " eq " ,
"Field" : " Address.Town " ,
"Value" : " New York "
}
]
}
}这种格式易于阅读和理解人类,易于扩展,易于序列化/挑选化,并且易于用于机器对机器通信。
Flexfetcher是为下一个平台构建的:
这意味着您可以在.NET Core(请参阅samples/WebApiSample )和.NET Framework(请参阅samples/WebApiSample.Framework48 )项目中使用它。
FlexFetcher支持用于过滤器和分角中使用的字段的下一个数据类型:
所有值可能都是无效的。
您可以通过运行下一个命令通过Nuget软件包管理器控制FlexFetcher(Nuget):
dotnet add package FlexFetcher
安装flexfetcher.ipendendencyindoction.microsoft(nuget):
dotnet add package FlexFetcher.DependencyInjection.Microsoft
安装flexfetcher.serialization.newtonsoftjson(nuget):
dotnet add package FlexFetcher.Serialization.NewtonsoftJson
安装FlexFetcher.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 ( ) ; 扩展方法适用于简单的情况,但是它们的用法非常有限。
For more complex cases you can use FlexFetcher classes: FlexFilter<TEntity> and FlexFilter<TEntity, TModel> , FlexSorter<TEntity> and FlexSorter<TEntity, TModel> , FlexPager<TEntity> and FlexPager<TEntity, TModel> , FlexFetcher<TEntity> and 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课程没有任何状态,因此可以安全地将其用作单例。但是,如果您想将它们用作范围或瞬态,则取决于您。
接下来将显示更高级的方案填充。另外samples/WebApiSample请在tests/FlexFetcherTests/DependencyInjectionTests/ServiceProviderTests.cs )和samples/WebApiSample.Framework48中查看更多示例。
在我们的示例数据模型中,我们具有嵌套对象:pesuerentity具有地址属性。让我们看看如何通过嵌套对象过滤:
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 and 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 } } 为了创建自己的过滤器操作员,需要:
BaseFilterExpressionHandler遗传的自定义filterexpressionHandlerFilterExpressionBuilderAddCustomExpressionHandlers方法看起来像这样(请参阅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 > > ( ) ;在此示例中,我们将“城镇”田地映射到“城镇”领域,即我们可以在过滤器和分类器中使用“城镇”而不是“城市”。
模型类的属性可以做同样的事情:
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 > > ( ) ;在此示例中,我们将equepentity.city属性映射到advellyModel.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 ) ;
在以前的示例中,我们仅使用实体的属性,但是可以使用具有自定义表达式的自定义字段。
它们可能用于Flexsorter,FlexFilters,FlexFetchers中。
假设我们想将自定义字段添加到peasonentity中:
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 > > ( ) ; 在大多数情况下,我们在上一节中看到的自定义字段就足够了,但是有时需要在过滤器中具有自定义表达式的自定义字段,以进行更复杂的过滤逻辑。
假设我们想将自定义字段“人组”添加到peopleentity,并将“ 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 ( ) ;
}
}当使用hideoriginalfields()时,自定义字段不会自动隐藏,因此应在需要时手动隐藏它们。
FlexFetcher设计用于机器对机器通信,因此能够序列化和挑选查询非常重要。
In the simple cases any JSON serializer can be used but as soos as you need to use fields with TimeOnly type or you need to serialize/deserialize arrays to use In operator, you need to apply settings and custom JSON converters from FlexFetcher.Serialization.NewtonsoftJson or FlexFetcher.Serialization.SystemTextJson packages.
安装FlexFetcher.Serialization.NewtonsoftJson软件包,并从Helper类获取设置:
var jsonSettings = NewtonsoftHelper . GetSerializerSettings ( ) ;
var json = JsonConvert . SerializeObject ( filter , jsonSettings ) ;
var deserializedFilter = JsonConvert . DeserializeObject < DataFilter > ( json , jsonSettings ) ;安装FlexFetcher.Serialization.SystemTextJson软件包,并从帮助班级获得设置:
var jsonSettings = SystemTextJsonHelper . GetSerializerOptions ( ) ;
var json = JsonSerializer . Serialize ( filter , jsonSettings ) ;
var deserializedFilter = JsonSerializer . Deserialize < DataFilter > ( json , jsonSettings ) ;还有一些JSON转换器允许像这样的简洁格式序列化/求解对象(dataFilter示例):
{
"L" : " And " ,
"Fs" : [
{
"O" : " Eq " ,
"F" : " Address.Town " ,
"V" : " New York "
}
]
}在tests/FlexFetcherTests/SerializationTests/NewtonsoftTests.cs和Tests/ samples/WebApiSample tests/FlexFetcherTests/SerializationTests/SystemTextJsonTests.cs samples/WebApiSample.Framework48 ,请参见更多简洁格式的示例。
为了支持简洁的格式,需要使用FlexFetcher.Serialization.NewtonsoftJson和FlexFetcher.Serialization.SystemTextJson使用下一个转换器。
FlexFetcherDataSorterConverterFlexFetcherDataSortersConverterFlexFetcherDataPagerConverterFlexFetcherDataFilterConverterFlexFetcherDataQueryConverter所有转换器都有readOnlyShortForm构造函数参数。如果设置为真,则只允许简洁的格式进行挑选。否则,将允许完整和简洁的格式。
通常,在大多数情况下,无需使用readOnlyShortForm ,但是如果您只想将避难所限制为简洁的格式,则可以将其设置为true。
flexfetcher可以在核心和框架的ASP.NET项目中使用,但是序列化配置不同。
需要下一步以在ASP.NET核心项目中配置序列化(System.Text.json的示例):
FlexFetcherModelBinderFlexFetcherModelBinderProviderAddControllers方法中的设置JSON序列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框架项目中配置序列化(newtonsoft.json的示例):
FlexFetcherModelBinderFlexFetcherModelBinderProviderWebApiConfig.cs中的设置JSON序列化设置类似: 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核心Web API项目samples/WebApiSample.Framework48 ASP.NET框架4.8 Web API项目这两个项目都具有相同的功能,并演示了如何在ASP.NET项目中使用FlexFetcher。
只需构建并运行它们即可查看Flexfetcher在实际项目中的工作方式。使用您喜欢的REST客户端将请求发送到API。请求的示例可以在samples/WebApiSample/ReadMe.md和samples/WebApiSample.Framework48/ReadMe.md中找到。
另外,在tests/FlexFetcherTests文件夹中还有测试,这些文件夹演示了如何在不同方案中使用FlexFetcher。