better way to inject interceptors into the dynamic query.
This commit is contained in:
parent
d01ac1601c
commit
de98b3b472
@ -6,15 +6,6 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Demo.DynamicQueries
|
||||
{
|
||||
public class SearchContactParamsService : IAlterQueryableService<Contact, Contact, SearchContactParams>
|
||||
{
|
||||
public Task<IQueryable<Contact>> AlterQueryableAsync(IQueryable<Contact> query, IDynamicQueryParams<SearchContactParams> dynamicQuery, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var safe = dynamicQuery.GetParams()?.SearchDisplayName;
|
||||
return Task.FromResult(query.Where(t => t.DisplayName.Contains(safe)));
|
||||
}
|
||||
}
|
||||
|
||||
public class ContactQueryableProvider : IQueryableProvider<Contact>
|
||||
{
|
||||
public Task<IQueryable<Contact>> GetQueryableAsync(object query, CancellationToken cancelllationToken = default)
|
||||
|
18
Demo/DynamicQueries/PersonConvertInterceptor.cs
Normal file
18
Demo/DynamicQueries/PersonConvertInterceptor.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using Demo.Queries;
|
||||
using PoweredSoft.DynamicQuery.Core;
|
||||
using System.Linq;
|
||||
|
||||
namespace Demo.DynamicQueries
|
||||
{
|
||||
public class PersonConvertInterceptor : IQueryConvertInterceptor<Person, PersonModel>
|
||||
{
|
||||
public PersonModel InterceptResultTo(Person entity)
|
||||
{
|
||||
return new PersonModel
|
||||
{
|
||||
Id = entity.Id,
|
||||
FullName = entity.FirstName + " " + entity.LastName
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
10
Demo/DynamicQueries/PersonModel.cs
Normal file
10
Demo/DynamicQueries/PersonModel.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Demo.DynamicQueries
|
||||
{
|
||||
public class PersonModel
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string FullName { get; set; }
|
||||
}
|
||||
}
|
54
Demo/DynamicQueries/PersonOptimizationInterceptor.cs
Normal file
54
Demo/DynamicQueries/PersonOptimizationInterceptor.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using Demo.Queries;
|
||||
using PoweredSoft.DynamicQuery;
|
||||
using PoweredSoft.DynamicQuery.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Demo.DynamicQueries
|
||||
{
|
||||
public class PersonOptimizationInterceptor : IFilterInterceptor, ISortInterceptor
|
||||
{
|
||||
public IFilter InterceptFilter(IFilter filter)
|
||||
{
|
||||
if (filter is ISimpleFilter simpleFilter)
|
||||
{
|
||||
if (simpleFilter.Path.Equals(nameof(PersonModel.FullName), System.StringComparison.InvariantCultureIgnoreCase))
|
||||
return new CompositeFilter
|
||||
{
|
||||
Type = filter.Type,
|
||||
And = filter.And,
|
||||
Filters = new List<IFilter> {
|
||||
new SimpleFilter
|
||||
{
|
||||
Not = simpleFilter.Not,
|
||||
And = false,
|
||||
Type = simpleFilter.Type,
|
||||
Value = simpleFilter.Value,
|
||||
Path = nameof(Person.FirstName)
|
||||
},
|
||||
new SimpleFilter
|
||||
{
|
||||
Not = simpleFilter.Not,
|
||||
And = false,
|
||||
Type = simpleFilter.Type,
|
||||
Value = simpleFilter.Value,
|
||||
Path = nameof(Person.LastName)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
public IEnumerable<ISort> InterceptSort(IEnumerable<ISort> sort)
|
||||
{
|
||||
foreach(var s in sort)
|
||||
{
|
||||
if (s.Path.Equals(nameof(PersonModel.FullName), System.StringComparison.InvariantCultureIgnoreCase))
|
||||
yield return new Sort(nameof(Person.LastName), s.Ascending);
|
||||
else
|
||||
yield return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
Demo/DynamicQueries/PersonQueryableProvider.cs
Normal file
33
Demo/DynamicQueries/PersonQueryableProvider.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using Demo.Queries;
|
||||
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Demo.DynamicQueries
|
||||
{
|
||||
public class PersonQueryableProvider : IQueryableProvider<Person>
|
||||
{
|
||||
private readonly IEnumerable<Person> _persons = new List<Person>()
|
||||
{
|
||||
new Person
|
||||
{
|
||||
Id = 1,
|
||||
FirstName = "David",
|
||||
LastName = "Lebee"
|
||||
},
|
||||
new Person
|
||||
{
|
||||
Id = 2,
|
||||
FirstName = "John",
|
||||
LastName = "Doe"
|
||||
}
|
||||
};
|
||||
|
||||
public Task<IQueryable<Person>> GetQueryableAsync(object query, CancellationToken cancelllationToken = default)
|
||||
{
|
||||
return Task.FromResult(_persons.AsQueryable());
|
||||
}
|
||||
}
|
||||
}
|
16
Demo/DynamicQueries/SearchContactParamsService.cs
Normal file
16
Demo/DynamicQueries/SearchContactParamsService.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Demo.DynamicQueries
|
||||
{
|
||||
public class SearchContactParamsService : IAlterQueryableService<Contact, Contact, SearchContactParams>
|
||||
{
|
||||
public Task<IQueryable<Contact>> AlterQueryableAsync(IQueryable<Contact> query, IDynamicQueryParams<SearchContactParams> dynamicQuery, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var safe = dynamicQuery.GetParams()?.SearchDisplayName;
|
||||
return Task.FromResult(query.Where(t => t.DisplayName.Contains(safe)));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,4 @@
|
||||
using PoweredSoft.CQRS.Abstractions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Demo.Queries
|
||||
{
|
||||
@ -18,33 +13,4 @@ namespace Demo.Queries
|
||||
{
|
||||
public string Search { get; set; }
|
||||
}
|
||||
|
||||
public class PersonQueryHandler : IQueryHandler<PersonQuery, IQueryable<Person>>
|
||||
{
|
||||
private readonly IEnumerable<Person> _persons = new List<Person>()
|
||||
{
|
||||
new Person
|
||||
{
|
||||
Id = 1,
|
||||
FirstName = "David",
|
||||
LastName = "Lebee"
|
||||
},
|
||||
new Person
|
||||
{
|
||||
Id = 2,
|
||||
FirstName = "John",
|
||||
LastName = "Doe"
|
||||
}
|
||||
};
|
||||
|
||||
public Task<IQueryable<Person>> HandleAsync(PersonQuery query, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var ret = _persons.AsQueryable();
|
||||
|
||||
if (query != null && !string.IsNullOrEmpty(query.Search))
|
||||
ret = ret.Where(t => t.FirstName.Contains(query.Search) || t.LastName.Contains(query.Search));
|
||||
|
||||
return Task.FromResult(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
29
Demo/Queries/PersonQueryHandler.cs
Normal file
29
Demo/Queries/PersonQueryHandler.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using PoweredSoft.CQRS.Abstractions;
|
||||
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Demo.Queries
|
||||
{
|
||||
public class PersonQueryHandler : IQueryHandler<PersonQuery, IQueryable<Person>>
|
||||
{
|
||||
private readonly IQueryableProvider<Person> queryableProvider;
|
||||
|
||||
public PersonQueryHandler(IQueryableProvider<Person> queryableProvider)
|
||||
{
|
||||
this.queryableProvider = queryableProvider;
|
||||
}
|
||||
|
||||
public async Task<IQueryable<Person>> HandleAsync(PersonQuery query, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var ret = await queryableProvider.GetQueryableAsync(query);
|
||||
|
||||
if (query != null && !string.IsNullOrEmpty(query.Search))
|
||||
ret = ret.Where(t => t.FirstName.Contains(query.Search) || t.LastName.Contains(query.Search));
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
@ -65,6 +65,12 @@ namespace Demo
|
||||
services.AddDynamicQuery<Contact>();
|
||||
services.AddDynamicQueryWithParams<Contact, SearchContactParams>(name: "SearchContacts")
|
||||
.AddAlterQueryableWithParams<Contact, SearchContactParams, SearchContactParamsService>();
|
||||
|
||||
services
|
||||
.AddTransient<IQueryableProvider<Person>, PersonQueryableProvider>()
|
||||
.AddDynamicQuery<Person, PersonModel>("People")
|
||||
.AddDynamicQueryInterceptor<Person, PersonModel, PersonConvertInterceptor>()
|
||||
.AddDynamicQueryInterceptor<Person, PersonModel, PersonOptimizationInterceptor>();
|
||||
}
|
||||
|
||||
private void AddCommands(IServiceCollection services)
|
||||
|
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
|
||||
{
|
||||
public class DynamicQueryInterceptorProvider<TSource, TDestination> : IDynamicQueryInterceptorProvider<TSource, TDestination>
|
||||
{
|
||||
private readonly Type[] types;
|
||||
|
||||
public DynamicQueryInterceptorProvider(params Type[] types)
|
||||
{
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
public IEnumerable<Type> GetInterceptorsTypes()
|
||||
{
|
||||
return types;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using PoweredSoft.DynamicQuery.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
|
||||
{
|
||||
public interface IDynamicQueryInterceptorProvider<TSource, TDestination>
|
||||
{
|
||||
IEnumerable<Type> GetInterceptorsTypes();
|
||||
}
|
||||
}
|
@ -16,7 +16,9 @@ namespace PoweredSoft.CQRS.DynamicQuery
|
||||
{
|
||||
public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync,
|
||||
IEnumerable<IQueryableProvider<TSource>> queryableProviders,
|
||||
IEnumerable<IAlterQueryableService<TSource, TDestination>> alterQueryableServices, IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, serviceProvider)
|
||||
IEnumerable<IAlterQueryableService<TSource, TDestination>> alterQueryableServices,
|
||||
IEnumerable<IDynamicQueryInterceptorProvider<TSource, TDestination>> dynamicQueryInterceptorProviders,
|
||||
IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, dynamicQueryInterceptorProviders, serviceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
@ -38,7 +40,9 @@ namespace PoweredSoft.CQRS.DynamicQuery
|
||||
public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync,
|
||||
IEnumerable<IQueryableProvider<TSource>> queryableProviders,
|
||||
IEnumerable<IAlterQueryableService<TSource, TDestination>> alterQueryableServices,
|
||||
IEnumerable<IAlterQueryableService<TSource, TDestination, TParams>> alterQueryableServicesWithParams, IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, serviceProvider)
|
||||
IEnumerable<IAlterQueryableService<TSource, TDestination, TParams>> alterQueryableServicesWithParams,
|
||||
IEnumerable<IDynamicQueryInterceptorProvider<TSource, TDestination>> dynamicQueryInterceptorProviders,
|
||||
IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, dynamicQueryInterceptorProviders, serviceProvider)
|
||||
{
|
||||
this.alterQueryableServicesWithParams = alterQueryableServicesWithParams;
|
||||
}
|
||||
|
@ -16,16 +16,19 @@ namespace PoweredSoft.CQRS.DynamicQuery
|
||||
private readonly IQueryHandlerAsync queryHandlerAsync;
|
||||
private readonly IEnumerable<IQueryableProvider<TSource>> queryableProviders;
|
||||
private readonly IEnumerable<IAlterQueryableService<TSource, TDestination>> alterQueryableServices;
|
||||
private readonly IEnumerable<IDynamicQueryInterceptorProvider<TSource, TDestination>> dynamicQueryInterceptorProviders;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
public DynamicQueryHandlerBase(IQueryHandlerAsync queryHandlerAsync,
|
||||
IEnumerable<IQueryableProvider<TSource>> queryableProviders,
|
||||
IEnumerable<IAlterQueryableService<TSource, TDestination>> alterQueryableServices,
|
||||
IEnumerable<IDynamicQueryInterceptorProvider<TSource, TDestination>> dynamicQueryInterceptorProviders,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
this.queryHandlerAsync = queryHandlerAsync;
|
||||
this.queryableProviders = queryableProviders;
|
||||
this.alterQueryableServices = alterQueryableServices;
|
||||
this.dynamicQueryInterceptorProviders = dynamicQueryInterceptorProviders;
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
@ -44,7 +47,9 @@ namespace PoweredSoft.CQRS.DynamicQuery
|
||||
|
||||
public virtual IEnumerable<IQueryInterceptor> GetInterceptors()
|
||||
{
|
||||
return Enumerable.Empty<IQueryInterceptor>();
|
||||
var types = dynamicQueryInterceptorProviders.SelectMany(t => t.GetInterceptorsTypes()).Distinct();
|
||||
foreach (var type in types)
|
||||
yield return serviceProvider.GetService(type) as IQueryInterceptor;
|
||||
}
|
||||
|
||||
protected async Task<IQueryExecutionResult<TDestination>> ProcessQueryAsync(IDynamicQuery query, CancellationToken cancellationToken = default)
|
||||
@ -54,23 +59,6 @@ namespace PoweredSoft.CQRS.DynamicQuery
|
||||
var options = GetQueryExecutionOptions(source, query);
|
||||
var interceptors = this.GetInterceptors();
|
||||
|
||||
// basic after read service.
|
||||
var afterReadService1 = this.serviceProvider.GetService(typeof(IAfterReadInterceptorAsync<TSource>));
|
||||
if (afterReadService1 is IQueryInterceptor ars1)
|
||||
queryHandlerAsync.AddInterceptor(ars1);
|
||||
|
||||
// support of injecting a query convert interceptor.
|
||||
if (typeof(TSource) != typeof(TDestination))
|
||||
{
|
||||
var convertService = this.serviceProvider.GetService(typeof(IQueryConvertInterceptor<TSource, TDestination>));
|
||||
if (convertService is IQueryInterceptor cs)
|
||||
queryHandlerAsync.AddInterceptor(cs);
|
||||
|
||||
var afterReadService2 = this.serviceProvider.GetService(typeof(IAfterReadInterceptorAsync<TSource, TDestination>));
|
||||
if (afterReadService2 is IQueryInterceptor ars2)
|
||||
queryHandlerAsync.AddInterceptor(ars2);
|
||||
}
|
||||
|
||||
foreach (var interceptor in interceptors)
|
||||
queryHandlerAsync.AddInterceptor(interceptor);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using PoweredSoft.CQRS.Abstractions;
|
||||
using PoweredSoft.CQRS.Abstractions.Discovery;
|
||||
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
|
||||
@ -95,22 +96,64 @@ namespace PoweredSoft.CQRS.DynamicQuery
|
||||
return services.AddTransient<IAlterQueryableService<TSource, TDestination, TParams>, TService>();
|
||||
}
|
||||
|
||||
public static IServiceCollection AddQueryConvertInterceptor<TSource, TDestination, TService>(this IServiceCollection services)
|
||||
where TService : class, IQueryConvertInterceptor<TSource, TDestination>
|
||||
public static IServiceCollection AddDynamicQueryInterceptor<TSource, TDestination, TInterceptor>(this IServiceCollection services)
|
||||
where TInterceptor : class, IQueryInterceptor
|
||||
{
|
||||
return services.AddTransient<IQueryConvertInterceptor<TSource, TDestination>, TService>();
|
||||
services.TryAddTransient<TInterceptor>();
|
||||
return services.AddSingleton<IDynamicQueryInterceptorProvider<TSource, TDestination>>(
|
||||
new DynamicQueryInterceptorProvider<TSource, TDestination>(typeof(TInterceptor)));
|
||||
}
|
||||
|
||||
public static IServiceCollection AddAfterReadInterceptorAsync<TSource, TService>(this IServiceCollection services)
|
||||
where TService : class, IAfterReadInterceptorAsync<TSource>
|
||||
public static IServiceCollection AddDynamicQueryInterceptors<TSource, TDestination, T1, T2>(this IServiceCollection services)
|
||||
where T1 : class, IQueryInterceptor
|
||||
where T2 : class, IQueryInterceptor
|
||||
{
|
||||
return services.AddTransient<IAfterReadInterceptorAsync<TSource>, TService>();
|
||||
services.TryAddTransient<T1>();
|
||||
services.TryAddTransient<T2>();
|
||||
return services.AddSingleton<IDynamicQueryInterceptorProvider<TSource, TDestination>>(
|
||||
new DynamicQueryInterceptorProvider<TSource, TDestination>(typeof(T1), typeof(T2)));
|
||||
}
|
||||
|
||||
public static IServiceCollection AddAfterReadInterceptorAsync<TSource, TDestination, TService>(this IServiceCollection services)
|
||||
where TService : class, IAfterReadInterceptorAsync<TSource, TDestination>
|
||||
public static IServiceCollection AddDynamicQueryInterceptors<TSource, TDestination, T1, T2, T3>(this IServiceCollection services)
|
||||
where T1 : class, IQueryInterceptor
|
||||
where T2 : class, IQueryInterceptor
|
||||
where T3 : class, IQueryInterceptor
|
||||
{
|
||||
return services.AddTransient<IAfterReadInterceptorAsync<TSource, TDestination>, TService>();
|
||||
services.TryAddTransient<T1>();
|
||||
services.TryAddTransient<T2>();
|
||||
services.TryAddTransient<T3>();
|
||||
return services.AddSingleton<IDynamicQueryInterceptorProvider<TSource, TDestination>>(
|
||||
new DynamicQueryInterceptorProvider<TSource, TDestination>(typeof(T1), typeof(T2), typeof(T3)));
|
||||
}
|
||||
|
||||
public static IServiceCollection AddDynamicQueryInterceptors<TSource, TDestination, T1, T2, T3, T4>(this IServiceCollection services)
|
||||
where T1 : class, IQueryInterceptor
|
||||
where T2 : class, IQueryInterceptor
|
||||
where T3 : class, IQueryInterceptor
|
||||
where T4 : class, IQueryInterceptor
|
||||
{
|
||||
services.TryAddTransient<T1>();
|
||||
services.TryAddTransient<T2>();
|
||||
services.TryAddTransient<T3>();
|
||||
services.TryAddTransient<T4>();
|
||||
return services.AddSingleton<IDynamicQueryInterceptorProvider<TSource, TDestination>>(
|
||||
new DynamicQueryInterceptorProvider<TSource, TDestination>(typeof(T1), typeof(T2), typeof(T3), typeof(T4)));
|
||||
}
|
||||
|
||||
public static IServiceCollection AddDynamicQueryInterceptors<TSource, TDestination, T1, T2, T3, T4, T5>(this IServiceCollection services)
|
||||
where T1 : class, IQueryInterceptor
|
||||
where T2 : class, IQueryInterceptor
|
||||
where T3 : class, IQueryInterceptor
|
||||
where T4 : class, IQueryInterceptor
|
||||
where T5 : class, IQueryInterceptor
|
||||
{
|
||||
services.TryAddTransient<T1>();
|
||||
services.TryAddTransient<T2>();
|
||||
services.TryAddTransient<T3>();
|
||||
services.TryAddTransient<T4>();
|
||||
services.TryAddTransient<T5>();
|
||||
return services.AddSingleton<IDynamicQueryInterceptorProvider<TSource, TDestination>>(
|
||||
new DynamicQueryInterceptorProvider<TSource, TDestination>(typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user