update namespaces
refactor the name of the organisation
This commit is contained in:
		
							parent
							
								
									88c86513e9
								
							
						
					
					
						commit
						1c81288895
					
				@ -0,0 +1,14 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
 | 
			
		||||
public class CommandNameAttribute : Attribute
 | 
			
		||||
{
 | 
			
		||||
    public CommandNameAttribute(string name)
 | 
			
		||||
    {
 | 
			
		||||
        Name = name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public string Name { get; }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
 | 
			
		||||
public class QueryNameAttribute : Attribute
 | 
			
		||||
{
 | 
			
		||||
    public QueryNameAttribute(string name)
 | 
			
		||||
    {
 | 
			
		||||
        Name = name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public string Name { get; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/CommandMeta.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/CommandMeta.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
public sealed class CommandMeta : ICommandMeta
 | 
			
		||||
{
 | 
			
		||||
    public CommandMeta(Type commandType, Type serviceType, Type commandResultType)
 | 
			
		||||
    {
 | 
			
		||||
        CommandType = commandType;
 | 
			
		||||
        ServiceType = serviceType;
 | 
			
		||||
        CommandResultType = commandResultType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public CommandMeta(Type commandType, Type serviceType)
 | 
			
		||||
    {
 | 
			
		||||
        CommandType = commandType;
 | 
			
		||||
        ServiceType = serviceType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CommandNameAttribute NameAttribute => CommandType.GetCustomAttribute<CommandNameAttribute>();
 | 
			
		||||
 | 
			
		||||
    public string Name
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            var name = NameAttribute?.Name ?? CommandType.Name.Replace("Command", string.Empty);
 | 
			
		||||
            return name;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Type CommandType { get; }
 | 
			
		||||
    public Type ServiceType { get; }
 | 
			
		||||
    public Type CommandResultType { get; }
 | 
			
		||||
 | 
			
		||||
    public string LowerCamelCaseName
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrEmpty(Name))
 | 
			
		||||
                return Name;
 | 
			
		||||
 | 
			
		||||
            var name = Name;
 | 
			
		||||
            var firstLetter = Char.ToLowerInvariant(name[0]);
 | 
			
		||||
            var ret = $"{firstLetter}{name.Substring(1)}";
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/ICommandMeta.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/ICommandMeta.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
public interface ICommandMeta
 | 
			
		||||
{
 | 
			
		||||
    string Name { get; }
 | 
			
		||||
    Type CommandType { get; }
 | 
			
		||||
    Type ServiceType { get; }
 | 
			
		||||
    Type CommandResultType { get; }
 | 
			
		||||
    string LowerCamelCaseName { get; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/IQueryDiscovery.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/IQueryDiscovery.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
public interface IQueryDiscovery
 | 
			
		||||
{
 | 
			
		||||
    IQueryMeta FindQuery(string name);
 | 
			
		||||
    IQueryMeta FindQuery(Type queryType);
 | 
			
		||||
    IEnumerable<IQueryMeta> GetQueries();
 | 
			
		||||
    bool QueryExists(string name);
 | 
			
		||||
    bool QueryExists(Type queryType);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public interface ICommandDiscovery
 | 
			
		||||
{
 | 
			
		||||
    bool CommandExists(string name);
 | 
			
		||||
    bool CommandExists(Type commandType);
 | 
			
		||||
    ICommandMeta FindCommand(string name);
 | 
			
		||||
    ICommandMeta FindCommand(Type commandType);
 | 
			
		||||
    IEnumerable<ICommandMeta> GetCommands();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/IQueryMeta.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/IQueryMeta.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
public interface IQueryMeta
 | 
			
		||||
{
 | 
			
		||||
    string Name { get; }
 | 
			
		||||
    Type QueryType { get; }
 | 
			
		||||
    Type ServiceType { get; }
 | 
			
		||||
    Type QueryResultType { get; }
 | 
			
		||||
    string Category { get; }
 | 
			
		||||
    string LowerCamelCaseName { get; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/QueryMeta.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								OpenHarbor.CQRS.Abstractions/Discovery/QueryMeta.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
public class QueryMeta : IQueryMeta
 | 
			
		||||
{
 | 
			
		||||
    public QueryMeta(Type queryType, Type serviceType, Type queryResultType)
 | 
			
		||||
    {
 | 
			
		||||
        QueryType = queryType;
 | 
			
		||||
        ServiceType = serviceType;
 | 
			
		||||
        QueryResultType = queryResultType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual QueryNameAttribute NameAttribute => QueryType.GetCustomAttribute<QueryNameAttribute>();
 | 
			
		||||
 | 
			
		||||
    public virtual string Name
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            var name = NameAttribute?.Name ?? QueryType.Name.Replace("Query", string.Empty);
 | 
			
		||||
            return name;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public virtual Type QueryType { get; }
 | 
			
		||||
    public virtual Type ServiceType { get; }
 | 
			
		||||
    public virtual Type QueryResultType { get; }
 | 
			
		||||
    public virtual string Category => "BasicQuery";
 | 
			
		||||
 | 
			
		||||
    public string LowerCamelCaseName
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrEmpty(Name))
 | 
			
		||||
                return Name;
 | 
			
		||||
 | 
			
		||||
            var name = Name;
 | 
			
		||||
            var firstLetter = char.ToLowerInvariant(name[0]);
 | 
			
		||||
            var ret = $"{firstLetter}{name[1..]}";
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								OpenHarbor.CQRS.Abstractions/ICommandHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								OpenHarbor.CQRS.Abstractions/ICommandHandler.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions;
 | 
			
		||||
 | 
			
		||||
public interface ICommandHandler<in TCommand>
 | 
			
		||||
    where TCommand : class
 | 
			
		||||
{
 | 
			
		||||
    Task HandleAsync(TCommand command, CancellationToken cancellationToken = default);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public interface ICommandHandler<in TCommand, TCommandResult>
 | 
			
		||||
    where TCommand : class
 | 
			
		||||
{
 | 
			
		||||
    Task<TCommandResult> HandleAsync(TCommand command, CancellationToken cancellationToken = default);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								OpenHarbor.CQRS.Abstractions/IQueryHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								OpenHarbor.CQRS.Abstractions/IQueryHandler.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions;
 | 
			
		||||
 | 
			
		||||
public interface IQueryHandler<in TQuery, TQueryResult>
 | 
			
		||||
    where TQuery : class
 | 
			
		||||
{
 | 
			
		||||
    Task<TQueryResult> HandleAsync(TQuery query, CancellationToken cancellationToken = default);
 | 
			
		||||
}
 | 
			
		||||
@ -1,10 +1,9 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>netstandard2.1</TargetFramework>
 | 
			
		||||
    <Copyright>Powered Softwares Inc.</Copyright>
 | 
			
		||||
    <PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro</PackageIconUrl>
 | 
			
		||||
    <Company>PoweredSoft</Company>
 | 
			
		||||
    <Authors>PoweredSoft Team</Authors>
 | 
			
		||||
    <PackageIconUrl>https://avatars.githubusercontent.com/u/52874619?v=4</PackageIconUrl>
 | 
			
		||||
    <Authors>David Lebee, Mathias Beaulieu-Duncan</Authors>
 | 
			
		||||
    <LangVersion>default</LangVersion>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Security;
 | 
			
		||||
 | 
			
		||||
public enum AuthorizationResult
 | 
			
		||||
{
 | 
			
		||||
    Unauthorized,
 | 
			
		||||
    Forbidden,
 | 
			
		||||
    Allowed
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,10 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Security;
 | 
			
		||||
 | 
			
		||||
public interface ICommandAuthorizationService
 | 
			
		||||
{
 | 
			
		||||
    Task<AuthorizationResult> IsAllowedAsync(Type commandType, CancellationToken cancellationToken = default);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,10 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions.Security;
 | 
			
		||||
 | 
			
		||||
public interface IQueryAuthorizationService
 | 
			
		||||
{
 | 
			
		||||
    Task<AuthorizationResult> IsAllowedAsync(Type queryType, CancellationToken cancellationToken = default);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								OpenHarbor.CQRS.Abstractions/ServiceCollectionExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								OpenHarbor.CQRS.Abstractions/ServiceCollectionExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Abstractions;
 | 
			
		||||
 | 
			
		||||
public static class ServiceCollectionExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static IServiceCollection AddQuery<TQuery, TQueryResult, TQueryHandler>(this IServiceCollection services)
 | 
			
		||||
        where TQuery : class
 | 
			
		||||
        where TQueryHandler : class, IQueryHandler<TQuery, TQueryResult>
 | 
			
		||||
    {
 | 
			
		||||
        // add handler to DI.
 | 
			
		||||
        services.AddTransient<IQueryHandler<TQuery, TQueryResult>, TQueryHandler>();
 | 
			
		||||
 | 
			
		||||
        // add for discovery purposes.
 | 
			
		||||
        var queryMeta = new QueryMeta(typeof(TQuery), typeof(IQueryHandler<TQuery, TQueryResult>), typeof(TQueryResult));
 | 
			
		||||
        services.AddSingleton<IQueryMeta>(queryMeta);
 | 
			
		||||
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddCommand<TCommand, TCommandResult, TCommandHandler>(this IServiceCollection services)
 | 
			
		||||
        where TCommand : class
 | 
			
		||||
        where TCommandHandler : class, ICommandHandler<TCommand, TCommandResult>
 | 
			
		||||
    {
 | 
			
		||||
        // add handler to DI.
 | 
			
		||||
        services.AddTransient<ICommandHandler<TCommand, TCommandResult>, TCommandHandler>();
 | 
			
		||||
 | 
			
		||||
        // add for discovery purposes.
 | 
			
		||||
        var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler<TCommand>), typeof(TCommandResult));
 | 
			
		||||
        services.AddSingleton<ICommandMeta>(commandMeta);
 | 
			
		||||
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddCommand<TCommand, TCommandHandler>(this IServiceCollection services)
 | 
			
		||||
        where TCommand : class
 | 
			
		||||
        where TCommandHandler : class, ICommandHandler<TCommand>
 | 
			
		||||
    {
 | 
			
		||||
        // add handler to DI.
 | 
			
		||||
        services.AddTransient<ICommandHandler<TCommand>, TCommandHandler>();
 | 
			
		||||
 | 
			
		||||
        // add for discovery purposes.
 | 
			
		||||
        var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler<TCommand>));
 | 
			
		||||
        services.AddSingleton<ICommandMeta>(commandMeta);
 | 
			
		||||
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
 | 
			
		||||
public class CommandControllerIgnoreAttribute : Attribute
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
 | 
			
		||||
public class QueryControllerIgnoreAttribute : Attribute
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>netstandard2.1</TargetFramework>
 | 
			
		||||
    <PackageIconUrl>https://avatars.githubusercontent.com/u/52874619?v=4</PackageIconUrl>
 | 
			
		||||
    <Authors>David Lebee, Mathias Beaulieu-Duncan</Authors>
 | 
			
		||||
    <LangVersion>default</LangVersion>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										38
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/CommandController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/CommandController.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
[Produces("application/json")]
 | 
			
		||||
[ApiController, Route("api/command/[controller]")]
 | 
			
		||||
public class CommandController<TCommand> : Controller
 | 
			
		||||
    where TCommand : class
 | 
			
		||||
{
 | 
			
		||||
    [HttpPost, CommandControllerAuthorization]
 | 
			
		||||
    public async Task<IActionResult> Handle([FromServices] ICommandHandler<TCommand> handler, 
 | 
			
		||||
        [FromBody] TCommand command)
 | 
			
		||||
    {
 | 
			
		||||
        if (!ModelState.IsValid)
 | 
			
		||||
            return BadRequest(ModelState);
 | 
			
		||||
 | 
			
		||||
        await handler.HandleAsync(command, this.Request.HttpContext.RequestAborted);
 | 
			
		||||
        return Ok();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[Produces("application/json")]
 | 
			
		||||
[ApiController, Route("api/command/[controller]")]
 | 
			
		||||
public class CommandController<TCommand, TTCommandResult> : Controller
 | 
			
		||||
    where TCommand : class
 | 
			
		||||
{
 | 
			
		||||
    [HttpPost, CommandControllerAuthorization]
 | 
			
		||||
    public async Task<ActionResult<TTCommandResult>> Handle([FromServices] ICommandHandler<TCommand, TTCommandResult> handler,
 | 
			
		||||
        [FromBody] TCommand command)
 | 
			
		||||
    {
 | 
			
		||||
        if (!ModelState.IsValid)
 | 
			
		||||
            return BadRequest(ModelState);
 | 
			
		||||
 | 
			
		||||
        return Ok(await handler.HandleAsync(command, this.Request.HttpContext.RequestAborted));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,43 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Filters;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Security;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class CommandControllerAsyncAuthorizationFilter : IAsyncAuthorizationFilter
 | 
			
		||||
{
 | 
			
		||||
    private readonly ICommandAuthorizationService _authorizationService;
 | 
			
		||||
 | 
			
		||||
    public CommandControllerAsyncAuthorizationFilter(IServiceProvider serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
        _authorizationService = serviceProvider.GetService<ICommandAuthorizationService>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
 | 
			
		||||
    {
 | 
			
		||||
        if (_authorizationService == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var action = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
 | 
			
		||||
        if (action == null)
 | 
			
		||||
            throw new Exception("Only Supports controller action descriptor");
 | 
			
		||||
 | 
			
		||||
        var attribute = action.MethodInfo.GetCustomAttribute<CommandControllerAuthorizationAttribute>();
 | 
			
		||||
        Type commandType;
 | 
			
		||||
        if (attribute?.CommandType != null)
 | 
			
		||||
            commandType = attribute.CommandType;
 | 
			
		||||
        else
 | 
			
		||||
            commandType = action.ControllerTypeInfo.GenericTypeArguments.First();
 | 
			
		||||
 | 
			
		||||
        var ar = await _authorizationService.IsAllowedAsync(commandType);
 | 
			
		||||
        if (ar == AuthorizationResult.Forbidden)
 | 
			
		||||
            context.Result = new StatusCodeResult(403);
 | 
			
		||||
        else if(ar == AuthorizationResult.Unauthorized)
 | 
			
		||||
            context.Result = new StatusCodeResult(401);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Method)]
 | 
			
		||||
public class CommandControllerAuthorizationAttribute : TypeFilterAttribute
 | 
			
		||||
{
 | 
			
		||||
    public CommandControllerAuthorizationAttribute() : base(typeof(CommandControllerAsyncAuthorizationFilter))
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public CommandControllerAuthorizationAttribute(Type commandType) : base(typeof(CommandControllerAsyncAuthorizationFilter))
 | 
			
		||||
    {
 | 
			
		||||
        CommandType = commandType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Type CommandType { get; } = null;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class CommandControllerConvention : IControllerModelConvention
 | 
			
		||||
{
 | 
			
		||||
    private readonly IServiceProvider _serviceProvider;
 | 
			
		||||
 | 
			
		||||
    public CommandControllerConvention(IServiceProvider serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
        this._serviceProvider = serviceProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Apply(ControllerModel controller)
 | 
			
		||||
    {
 | 
			
		||||
        if (!controller.ControllerType.IsGenericType)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!controller.ControllerType.Name.Contains("CommandController"))
 | 
			
		||||
            return;
 | 
			
		||||
        
 | 
			
		||||
        if (controller.ControllerType.Assembly != typeof(CommandControllerConvention).Assembly)
 | 
			
		||||
            return;
 | 
			
		||||
            
 | 
			
		||||
        var genericType = controller.ControllerType.GenericTypeArguments[0];
 | 
			
		||||
        var commandDiscovery = this._serviceProvider.GetRequiredService<ICommandDiscovery>();
 | 
			
		||||
        var command = commandDiscovery.FindCommand(genericType);
 | 
			
		||||
        controller.ControllerName = command.LowerCamelCaseName;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,43 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Controllers;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
using OpenHarbor.CQRS.AspNetCore.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class CommandControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
 | 
			
		||||
{
 | 
			
		||||
    private readonly ServiceProvider _serviceProvider;
 | 
			
		||||
 | 
			
		||||
    public CommandControllerFeatureProvider(ServiceProvider serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
        this._serviceProvider = serviceProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
 | 
			
		||||
    {
 | 
			
		||||
        var commandDiscovery = this._serviceProvider.GetRequiredService<ICommandDiscovery>();
 | 
			
		||||
        foreach (var f in commandDiscovery.GetCommands())
 | 
			
		||||
        {
 | 
			
		||||
            var ignoreAttribute = f.CommandType.GetCustomAttribute<CommandControllerIgnoreAttribute>();
 | 
			
		||||
            if (ignoreAttribute != null)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (f.CommandResultType == null)
 | 
			
		||||
            {
 | 
			
		||||
                var controllerType = typeof(CommandController<>).MakeGenericType(f.CommandType);
 | 
			
		||||
                var controllerTypeInfo = controllerType.GetTypeInfo();
 | 
			
		||||
                feature.Controllers.Add(controllerTypeInfo);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var controllerType = typeof(CommandController<,>).MakeGenericType(f.CommandType, f.CommandResultType);
 | 
			
		||||
                var controllerTypeInfo = controllerType.GetTypeInfo();
 | 
			
		||||
                feature.Controllers.Add(controllerTypeInfo);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,6 @@
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class CommandControllerOptions
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/MvcBuilderExensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/MvcBuilderExensions.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public static class MvcBuilderExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static IMvcBuilder AddPoweredSoftQueries(this IMvcBuilder builder, Action<QueryControllerOptions> configuration = null)
 | 
			
		||||
    {
 | 
			
		||||
        var options = new QueryControllerOptions();
 | 
			
		||||
        configuration?.Invoke(options);
 | 
			
		||||
        var services = builder.Services;
 | 
			
		||||
        var serviceProvider = services.BuildServiceProvider();
 | 
			
		||||
        builder.AddMvcOptions(o => o.Conventions.Add(new QueryControllerConvention(serviceProvider)));
 | 
			
		||||
        builder.ConfigureApplicationPartManager(m => m.FeatureProviders.Add(new QueryControllerFeatureProvider(serviceProvider)));
 | 
			
		||||
        return builder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IMvcBuilder AddPoweredSoftCommands(this IMvcBuilder builder)
 | 
			
		||||
    {
 | 
			
		||||
        var services = builder.Services;
 | 
			
		||||
        var serviceProvider = services.BuildServiceProvider();
 | 
			
		||||
        builder.AddMvcOptions(o => o.Conventions.Add(new CommandControllerConvention(serviceProvider)));
 | 
			
		||||
        builder.ConfigureApplicationPartManager(m => m.FeatureProviders.Add(new CommandControllerFeatureProvider(serviceProvider)));
 | 
			
		||||
        return builder;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/QueryController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/QueryController.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
[Produces("application/json")]
 | 
			
		||||
[ApiController, Route("api/query/[controller]")]
 | 
			
		||||
public class QueryController<TQuery, TQueryResult> : Controller
 | 
			
		||||
    where TQuery : class
 | 
			
		||||
{
 | 
			
		||||
    [HttpPost, QueryControllerAuthorization]
 | 
			
		||||
    public async Task<ActionResult<TQueryResult>> Handle([FromServices] IQueryHandler<TQuery, TQueryResult> handler, 
 | 
			
		||||
        [FromBody] TQuery query)
 | 
			
		||||
    {
 | 
			
		||||
        if (!ModelState.IsValid)
 | 
			
		||||
            return BadRequest(ModelState);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return Ok(await handler.HandleAsync(query, this.Request.HttpContext.RequestAborted));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [HttpGet, QueryControllerAuthorization]
 | 
			
		||||
    public async Task<ActionResult<TQueryResult>> HandleGet([FromServices] IQueryHandler<TQuery, TQueryResult> handler,
 | 
			
		||||
        [FromQuery] TQuery query)
 | 
			
		||||
    {
 | 
			
		||||
        if (!ModelState.IsValid)
 | 
			
		||||
            return BadRequest(ModelState);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return Ok(await handler.HandleAsync(query, this.Request.HttpContext.RequestAborted));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,43 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Filters;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Security;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class QueryControllerAsyncAuthorizationFilter : IAsyncAuthorizationFilter
 | 
			
		||||
{
 | 
			
		||||
    private readonly IQueryAuthorizationService _authorizationService;
 | 
			
		||||
 | 
			
		||||
    public QueryControllerAsyncAuthorizationFilter(IServiceProvider serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
        _authorizationService = serviceProvider.GetService<IQueryAuthorizationService>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
 | 
			
		||||
    {
 | 
			
		||||
        if (_authorizationService == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var action = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
 | 
			
		||||
        if (action == null)
 | 
			
		||||
            throw new Exception("Only Supports controller action descriptor");
 | 
			
		||||
 | 
			
		||||
        var attribute = action.MethodInfo.GetCustomAttribute<QueryControllerAuthorizationAttribute>();
 | 
			
		||||
        Type queryType;
 | 
			
		||||
        if (attribute?.QueryType != null)
 | 
			
		||||
            queryType = attribute.QueryType;
 | 
			
		||||
        else
 | 
			
		||||
            queryType = action.ControllerTypeInfo.GenericTypeArguments.First();
 | 
			
		||||
 | 
			
		||||
        var ar = await _authorizationService.IsAllowedAsync(queryType);
 | 
			
		||||
        if (ar == AuthorizationResult.Forbidden)
 | 
			
		||||
            context.Result = new StatusCodeResult(403);
 | 
			
		||||
        else if (ar == AuthorizationResult.Unauthorized)
 | 
			
		||||
            context.Result = new StatusCodeResult(401);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
[AttributeUsage(AttributeTargets.Method)]
 | 
			
		||||
public class QueryControllerAuthorizationAttribute : TypeFilterAttribute
 | 
			
		||||
{
 | 
			
		||||
    public QueryControllerAuthorizationAttribute() : base(typeof(QueryControllerAsyncAuthorizationFilter))
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public QueryControllerAuthorizationAttribute(Type queryType) : base(typeof(QueryControllerAsyncAuthorizationFilter))
 | 
			
		||||
    {
 | 
			
		||||
        QueryType = queryType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Type QueryType { get; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerConvention.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerConvention.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class QueryControllerConvention : IControllerModelConvention
 | 
			
		||||
{
 | 
			
		||||
    private readonly IServiceProvider _serviceProvider;
 | 
			
		||||
 | 
			
		||||
    public QueryControllerConvention(IServiceProvider serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
        _serviceProvider = serviceProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Apply(ControllerModel controller)
 | 
			
		||||
    {
 | 
			
		||||
        if (controller.ControllerType.IsGenericType && controller.ControllerType.Name.Contains("QueryController") && controller.ControllerType.Assembly == typeof(QueryControllerConvention).Assembly)
 | 
			
		||||
        {
 | 
			
		||||
            var genericType = controller.ControllerType.GenericTypeArguments[0];
 | 
			
		||||
            var queryDiscovery = _serviceProvider.GetRequiredService<IQueryDiscovery>();
 | 
			
		||||
            var query = queryDiscovery.FindQuery(genericType);
 | 
			
		||||
            controller.ControllerName = query.LowerCamelCaseName;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,37 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Controllers;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
using OpenHarbor.CQRS.AspNetCore.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class QueryControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
 | 
			
		||||
{
 | 
			
		||||
    private readonly ServiceProvider _serviceProvider;
 | 
			
		||||
 | 
			
		||||
    public QueryControllerFeatureProvider(ServiceProvider serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
        _serviceProvider = serviceProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
 | 
			
		||||
    {
 | 
			
		||||
        var queryDiscovery = this._serviceProvider.GetRequiredService<IQueryDiscovery>();
 | 
			
		||||
        foreach (var f in queryDiscovery.GetQueries())
 | 
			
		||||
        {
 | 
			
		||||
            var ignoreAttribute = f.QueryType.GetCustomAttribute<QueryControllerIgnoreAttribute>();
 | 
			
		||||
            if (ignoreAttribute != null)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (f.Category != "BasicQuery")
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            var controllerType = typeof(QueryController<,>).MakeGenericType(f.QueryType, f.QueryResultType);
 | 
			
		||||
            var controllerTypeInfo = controllerType.GetTypeInfo();
 | 
			
		||||
            feature.Controllers.Add(controllerTypeInfo);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerOptions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerOptions.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
namespace OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class QueryControllerOptions
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								OpenHarbor.CQRS.AspNetCore/OpenHarbor.CQRS.AspNetCore.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								OpenHarbor.CQRS.AspNetCore/OpenHarbor.CQRS.AspNetCore.csproj
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net8.0</TargetFramework>
 | 
			
		||||
    <PackageIconUrl>https://avatars.githubusercontent.com/u/52874619?v=4</PackageIconUrl>
 | 
			
		||||
    <Authors>David Lebee, Mathias Beaulieu-Duncan</Authors>
 | 
			
		||||
    <IsAotCompatible>true</IsAotCompatible>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS.Abstractions\OpenHarbor.CQRS.Abstractions.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS.AspNetCore.Abstractions\OpenHarbor.CQRS.AspNetCore.Abstractions.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@ -0,0 +1,19 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
 | 
			
		||||
public class DynamicQueryInterceptorProvider<TSource, TDestination> : IDynamicQueryInterceptorProvider<TSource, TDestination>
 | 
			
		||||
{
 | 
			
		||||
    private readonly Type[] _types;
 | 
			
		||||
 | 
			
		||||
    public DynamicQueryInterceptorProvider(params Type[] types)
 | 
			
		||||
    {
 | 
			
		||||
        _types = types;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IEnumerable<Type> GetInterceptorsTypes()
 | 
			
		||||
    {
 | 
			
		||||
        return _types;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,16 @@
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
 | 
			
		||||
public interface IAlterQueryableService<TSource, TDestination>
 | 
			
		||||
{
 | 
			
		||||
    Task<IQueryable<TSource>> AlterQueryableAsync(IQueryable<TSource> query, IDynamicQuery dynamicQuery, CancellationToken cancellationToken = default);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public interface IAlterQueryableService<TSource, TDestination, in TParams>
 | 
			
		||||
    where TParams : class
 | 
			
		||||
{
 | 
			
		||||
    Task<IQueryable<TSource>> AlterQueryableAsync(IQueryable<TSource> query, IDynamicQueryParams<TParams> dynamicQuery, CancellationToken cancellationToken = default);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQuery.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQuery.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
 | 
			
		||||
public interface IDynamicQuery<TSource, TDestination> : IDynamicQuery
 | 
			
		||||
    where TSource : class
 | 
			
		||||
    where TDestination : class
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public interface IDynamicQuery<TSource, TDestination, out TParams> : IDynamicQuery<TSource, TDestination>, IDynamicQueryParams<TParams>
 | 
			
		||||
    where TSource : class
 | 
			
		||||
    where TDestination : class
 | 
			
		||||
    where TParams : class
 | 
			
		||||
{
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public interface IDynamicQuery
 | 
			
		||||
{
 | 
			
		||||
    List<IFilter> GetFilters();
 | 
			
		||||
    List<IGroup> GetGroups();
 | 
			
		||||
    List<ISort> GetSorts();
 | 
			
		||||
    List<IAggregate> GetAggregates();
 | 
			
		||||
    int? GetPage();
 | 
			
		||||
    int? GetPageSize();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,9 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
    
 | 
			
		||||
public interface IDynamicQueryInterceptorProvider<TSource, TDestination>
 | 
			
		||||
{
 | 
			
		||||
    IEnumerable<Type> GetInterceptorsTypes();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
 | 
			
		||||
public interface IDynamicQueryParams<out TParams>
 | 
			
		||||
    where TParams : class
 | 
			
		||||
{
 | 
			
		||||
    TParams GetParams();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,10 @@
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
 | 
			
		||||
public interface IQueryableProvider<TSource>
 | 
			
		||||
{
 | 
			
		||||
    Task<IQueryable<TSource>> GetQueryableAsync(object query, CancellationToken cancellationToken = default);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,13 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>netstandard2.1</TargetFramework>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <PackageIconUrl>https://avatars.githubusercontent.com/u/52874619?v=4</PackageIconUrl>
 | 
			
		||||
    <Authors>David Lebee, Mathias Beaulieu-Duncan</Authors>
 | 
			
		||||
    <LangVersion>default</LangVersion>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="PoweredSoft.DynamicQuery.Core" Version="3.0.1" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										68
									
								
								OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQuery.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQuery.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
using PoweredSoft.DynamicQuery;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.AspNetCore;
 | 
			
		||||
 | 
			
		||||
public class DynamicQuery<TSource, TDestination> : DynamicQuery, IDynamicQuery<TSource, TDestination>
 | 
			
		||||
        where TSource : class
 | 
			
		||||
        where TDestination : class
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class DynamicQuery<TSource, TDestination, TParams> : DynamicQuery, IDynamicQuery<TSource, TDestination, TParams>
 | 
			
		||||
    where TSource : class
 | 
			
		||||
    where TDestination : class
 | 
			
		||||
    where TParams : class
 | 
			
		||||
{
 | 
			
		||||
    public TParams Params { get; set; }
 | 
			
		||||
 | 
			
		||||
    public TParams GetParams()
 | 
			
		||||
    {
 | 
			
		||||
        return Params;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class DynamicQuery : IDynamicQuery
 | 
			
		||||
{
 | 
			
		||||
    public int? Page { get; set; }
 | 
			
		||||
    public int? PageSize { get; set; }
 | 
			
		||||
    public List<Sort> Sorts { get; set; }
 | 
			
		||||
    public List<DynamicQueryAggregate> Aggregates { get; set; }
 | 
			
		||||
    public List<Group> Groups { get; set; }
 | 
			
		||||
    public List<DynamicQueryFilter> Filters { get; set; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public List<IAggregate> GetAggregates()
 | 
			
		||||
    {
 | 
			
		||||
        return Aggregates?.Select(t => t.ToAggregate())?.ToList();//.AsEnumerable<IAggregate>()?.ToList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<IFilter> GetFilters()
 | 
			
		||||
    {
 | 
			
		||||
        return Filters?.Select(t => t.ToFilter())?.ToList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<IGroup> GetGroups()
 | 
			
		||||
    {
 | 
			
		||||
        return this.Groups?.AsEnumerable<IGroup>()?.ToList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int? GetPage()
 | 
			
		||||
    {
 | 
			
		||||
        return this.Page;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int? GetPageSize()
 | 
			
		||||
    {
 | 
			
		||||
        return this.PageSize;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<ISort> GetSorts()
 | 
			
		||||
    {
 | 
			
		||||
        return this.Sorts?.AsEnumerable<ISort>()?.ToList();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
using PoweredSoft.DynamicQuery;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.AspNetCore;
 | 
			
		||||
 | 
			
		||||
public class DynamicQueryAggregate
 | 
			
		||||
{
 | 
			
		||||
    public string Path { get; set; }
 | 
			
		||||
    public string Type { get; set; }
 | 
			
		||||
 | 
			
		||||
    public IAggregate ToAggregate()
 | 
			
		||||
    {
 | 
			
		||||
        return new Aggregate
 | 
			
		||||
        {
 | 
			
		||||
            Type = Enum.Parse<AggregateType>(Type),
 | 
			
		||||
            Path = Path
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,88 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using PoweredSoft.DynamicQuery;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.AspNetCore;
 | 
			
		||||
 | 
			
		||||
public class DynamicQueryFilter
 | 
			
		||||
{
 | 
			
		||||
    public List<DynamicQueryFilter> Filters { get; set; }
 | 
			
		||||
    public bool? And { get; set; }
 | 
			
		||||
    public string Type { get; set; }
 | 
			
		||||
    public bool? Not { get; set; }
 | 
			
		||||
    public string Path { get; set; }
 | 
			
		||||
    public object Value { get; set; }
 | 
			
		||||
 | 
			
		||||
    [FromQuery(Name ="value")]
 | 
			
		||||
    public string QueryValue
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            Value = value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool? CaseInsensitive { get; set; }
 | 
			
		||||
 | 
			
		||||
    public IFilter ToFilter()
 | 
			
		||||
    {
 | 
			
		||||
        var type = Enum.Parse<FilterType>(Type);
 | 
			
		||||
        if (type == FilterType.Composite)
 | 
			
		||||
        {
 | 
			
		||||
            var compositeFilter = new CompositeFilter
 | 
			
		||||
            {
 | 
			
		||||
                And = And,
 | 
			
		||||
                Type = FilterType.Composite,
 | 
			
		||||
                Filters = Filters?.Select(t => t.ToFilter())?.ToList() ?? new List<IFilter>()
 | 
			
		||||
            };
 | 
			
		||||
            return compositeFilter;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        object value = Value;
 | 
			
		||||
        if (Value is JsonElement jsonElement)
 | 
			
		||||
        {
 | 
			
		||||
            switch (jsonElement.ValueKind)
 | 
			
		||||
            {
 | 
			
		||||
                case JsonValueKind.String:
 | 
			
		||||
                    value = jsonElement.ToString();
 | 
			
		||||
                    break;
 | 
			
		||||
                case JsonValueKind.Number:
 | 
			
		||||
                    if (jsonElement.ToString().Contains('.'))
 | 
			
		||||
                        value = jsonElement.GetDecimal();
 | 
			
		||||
                    else if (jsonElement.TryGetInt64(out var convertedValue))
 | 
			
		||||
                        value = convertedValue;
 | 
			
		||||
                    break;
 | 
			
		||||
                case JsonValueKind.True:
 | 
			
		||||
                    value = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                case JsonValueKind.False:
 | 
			
		||||
                    value = false;
 | 
			
		||||
                    break;
 | 
			
		||||
                // TODO: Array support
 | 
			
		||||
                default:
 | 
			
		||||
                    value = null;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var simpleFilter = new SimpleFilter
 | 
			
		||||
        {
 | 
			
		||||
            And = And,
 | 
			
		||||
            Type = type,
 | 
			
		||||
            Not = Not,
 | 
			
		||||
            Path = Path,
 | 
			
		||||
            Value = value,
 | 
			
		||||
            CaseInsensitive = CaseInsensitive,
 | 
			
		||||
        };
 | 
			
		||||
        return simpleFilter;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,61 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions;
 | 
			
		||||
using OpenHarbor.CQRS.AspNetCore.Mvc;
 | 
			
		||||
using OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
[ApiController, Route("api/query/[controller]")]
 | 
			
		||||
public class DynamicQueryController<TSource, TDestination> : Controller
 | 
			
		||||
    where TSource : class
 | 
			
		||||
    where TDestination : class
 | 
			
		||||
{
 | 
			
		||||
    [HttpPost, QueryControllerAuthorization]
 | 
			
		||||
    public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
 | 
			
		||||
            [FromBody] DynamicQuery<TSource, TDestination> query, 
 | 
			
		||||
            [FromServices]IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [HttpGet, QueryControllerAuthorization]
 | 
			
		||||
    public async Task<IQueryExecutionResult<TDestination>> HandleGetAsync(
 | 
			
		||||
            [FromQuery] DynamicQuery<TSource, TDestination> query,
 | 
			
		||||
            [FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[ApiController, Route("api/query/[controller]")]
 | 
			
		||||
public class DynamicQueryController<TSource, TDestination, TParams> : Controller
 | 
			
		||||
    where TSource : class
 | 
			
		||||
    where TDestination : class
 | 
			
		||||
    where TParams : class
 | 
			
		||||
{
 | 
			
		||||
    [HttpPost, QueryControllerAuthorization]
 | 
			
		||||
    public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
 | 
			
		||||
            [FromBody] DynamicQuery<TSource, TDestination, TParams> query,
 | 
			
		||||
            [FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [HttpGet, QueryControllerAuthorization]
 | 
			
		||||
    public async Task<IQueryExecutionResult<TDestination>> HandleGetAsync(
 | 
			
		||||
            [FromQuery] DynamicQuery<TSource, TDestination, TParams> query,
 | 
			
		||||
            [FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class DynamicQueryControllerConvention : IControllerModelConvention
 | 
			
		||||
{
 | 
			
		||||
    private readonly IServiceProvider _serviceProvider;
 | 
			
		||||
 | 
			
		||||
    public DynamicQueryControllerConvention(IServiceProvider serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
        _serviceProvider = serviceProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Apply(ControllerModel controller)
 | 
			
		||||
    {
 | 
			
		||||
        if (controller.ControllerType.IsGenericType && controller.ControllerType.Name.Contains("DynamicQueryController") && controller.ControllerType.Assembly == typeof(DynamicQueryControllerConvention).Assembly)
 | 
			
		||||
        {
 | 
			
		||||
            var genericType = controller.ControllerType.GenericTypeArguments[0];
 | 
			
		||||
            var queryDiscovery = _serviceProvider.GetRequiredService<IQueryDiscovery>();
 | 
			
		||||
            var query = queryDiscovery.FindQuery(genericType);
 | 
			
		||||
            controller.ControllerName = query.LowerCamelCaseName;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,50 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Controllers;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
using OpenHarbor.CQRS.AspNetCore.Abstractions.Attributes;
 | 
			
		||||
using OpenHarbor.CQRS.DynamicQuery.Discover;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class DynamicQueryControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
 | 
			
		||||
{
 | 
			
		||||
    private readonly ServiceProvider _serviceProvider;
 | 
			
		||||
 | 
			
		||||
    public DynamicQueryControllerFeatureProvider(ServiceProvider serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
        _serviceProvider = serviceProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
 | 
			
		||||
    {
 | 
			
		||||
        var queryDiscovery = _serviceProvider.GetRequiredService<IQueryDiscovery>();
 | 
			
		||||
        foreach (var queryMeta in queryDiscovery.GetQueries())
 | 
			
		||||
        {
 | 
			
		||||
            var ignoreAttribute = queryMeta.QueryType.GetCustomAttribute<QueryControllerIgnoreAttribute>();
 | 
			
		||||
            if (ignoreAttribute != null)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (queryMeta.Category != "DynamicQuery")
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (queryMeta is DynamicQueryMeta dynamicQueryMeta)
 | 
			
		||||
            {
 | 
			
		||||
                if (dynamicQueryMeta.ParamsType == null)
 | 
			
		||||
                {
 | 
			
		||||
                    var controllerType = typeof(DynamicQueryController<,>).MakeGenericType(queryMeta.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType);
 | 
			
		||||
                    var controllerTypeInfo = controllerType.GetTypeInfo();
 | 
			
		||||
                    feature.Controllers.Add(controllerTypeInfo);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    var controllerType = typeof(DynamicQueryController<,,>).MakeGenericType(queryMeta.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType, dynamicQueryMeta.ParamsType);
 | 
			
		||||
                    var controllerTypeInfo = controllerType.GetTypeInfo();
 | 
			
		||||
                    feature.Controllers.Add(controllerTypeInfo);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,5 @@
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
public class DynamicQueryControllerOptions
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,19 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using OpenHarbor.CQRS.DynamicQuery.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.AspNetCore;
 | 
			
		||||
 | 
			
		||||
public static class MvcBuilderExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static IMvcBuilder AddPoweredSoftDynamicQueries(this IMvcBuilder builder, Action<DynamicQueryControllerOptions> configuration = null)
 | 
			
		||||
    {
 | 
			
		||||
        var options = new DynamicQueryControllerOptions();
 | 
			
		||||
        configuration?.Invoke(options);
 | 
			
		||||
        var services = builder.Services;
 | 
			
		||||
        var serviceProvider = services.BuildServiceProvider();
 | 
			
		||||
        builder.AddMvcOptions(o => o.Conventions.Add(new DynamicQueryControllerConvention(serviceProvider)));
 | 
			
		||||
        builder.ConfigureApplicationPartManager(m => m.FeatureProviders.Add(new DynamicQueryControllerFeatureProvider(serviceProvider)));
 | 
			
		||||
        return builder;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net8.0</TargetFramework>
 | 
			
		||||
    <PackageIconUrl>https://avatars.githubusercontent.com/u/52874619?v=4</PackageIconUrl>
 | 
			
		||||
    <Authors>David Lebee, Mathias Beaulieu-Duncan</Authors>
 | 
			
		||||
    <IsAotCompatible>true</IsAotCompatible>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS.Abstractions\OpenHarbor.CQRS.Abstractions.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS.AspNetCore.Abstractions\OpenHarbor.CQRS.AspNetCore.Abstractions.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS.AspNetCore\OpenHarbor.CQRS.AspNetCore.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS.DynamicQuery.Abstractions\OpenHarbor.CQRS.DynamicQuery.Abstractions.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS.DynamicQuery\OpenHarbor.CQRS.DynamicQuery.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										32
									
								
								OpenHarbor.CQRS.DynamicQuery/Discover/DynamicQueryMeta.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								OpenHarbor.CQRS.DynamicQuery/Discover/DynamicQueryMeta.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Pluralize.NET;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery.Discover;
 | 
			
		||||
 | 
			
		||||
public class DynamicQueryMeta : QueryMeta
 | 
			
		||||
{
 | 
			
		||||
    public DynamicQueryMeta(Type queryType, Type serviceType, Type queryResultType) : base(queryType, serviceType, queryResultType)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Type SourceType => QueryType.GetGenericArguments()[0];
 | 
			
		||||
    public Type DestinationType => QueryType.GetGenericArguments()[1];
 | 
			
		||||
    public override string Category => "DynamicQuery";
 | 
			
		||||
    public override string Name
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            if (OverridableName != null)
 | 
			
		||||
                return OverridableName;
 | 
			
		||||
 | 
			
		||||
            var pluralizer = new Pluralizer();
 | 
			
		||||
            return pluralizer.Pluralize(DestinationType.Name);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Type ParamsType { get; internal set; }
 | 
			
		||||
    public string OverridableName { get; internal set; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										67
									
								
								OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandler.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
			
		||||
using OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery;
 | 
			
		||||
 | 
			
		||||
public class DynamicQueryHandler<TSource, TDestination>
 | 
			
		||||
    : DynamicQueryHandlerBase<TSource, TDestination>, 
 | 
			
		||||
    OpenHarbor.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>>
 | 
			
		||||
    where TSource : class
 | 
			
		||||
    where TDestination : class
 | 
			
		||||
{
 | 
			
		||||
    public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync, 
 | 
			
		||||
        IEnumerable<IQueryableProvider<TSource>> queryableProviders,
 | 
			
		||||
        IEnumerable<IAlterQueryableService<TSource, TDestination>> alterQueryableServices, 
 | 
			
		||||
        IEnumerable<IDynamicQueryInterceptorProvider<TSource, TDestination>> dynamicQueryInterceptorProviders, 
 | 
			
		||||
        IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, dynamicQueryInterceptorProviders, serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Task<IQueryExecutionResult<TDestination>> HandleAsync(IDynamicQuery<TSource, TDestination> query, CancellationToken cancellationToken = default)
 | 
			
		||||
    {
 | 
			
		||||
        return ProcessQueryAsync(query, cancellationToken);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class DynamicQueryHandler<TSource, TDestination, TParams>
 | 
			
		||||
    : DynamicQueryHandlerBase<TSource, TDestination>, 
 | 
			
		||||
    OpenHarbor.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>>
 | 
			
		||||
    where TSource : class
 | 
			
		||||
    where TDestination : class
 | 
			
		||||
    where TParams : class
 | 
			
		||||
{
 | 
			
		||||
    private readonly IEnumerable<IAlterQueryableService<TSource, TDestination, TParams>> alterQueryableServicesWithParams;
 | 
			
		||||
 | 
			
		||||
    public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync, 
 | 
			
		||||
        IEnumerable<IQueryableProvider<TSource>> queryableProviders,
 | 
			
		||||
        IEnumerable<IAlterQueryableService<TSource, TDestination>> alterQueryableServices,
 | 
			
		||||
        IEnumerable<IAlterQueryableService<TSource, TDestination, TParams>> alterQueryableServicesWithParams, 
 | 
			
		||||
        IEnumerable<IDynamicQueryInterceptorProvider<TSource, TDestination>> dynamicQueryInterceptorProviders,
 | 
			
		||||
        IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, dynamicQueryInterceptorProviders, serviceProvider)
 | 
			
		||||
    {
 | 
			
		||||
        this.alterQueryableServicesWithParams = alterQueryableServicesWithParams;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override async Task<IQueryable<TSource>> AlterSourceAsync(IQueryable<TSource> source, IDynamicQuery query, CancellationToken cancellationToken)
 | 
			
		||||
    {
 | 
			
		||||
        source =  await base.AlterSourceAsync(source, query, cancellationToken);
 | 
			
		||||
 | 
			
		||||
        if (query is IDynamicQueryParams<TParams> withParams)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var it in alterQueryableServicesWithParams)
 | 
			
		||||
                source = await it.AlterQueryableAsync(source, withParams, cancellationToken);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return source;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Task<IQueryExecutionResult<TDestination>> HandleAsync(IDynamicQuery<TSource, TDestination, TParams> query, CancellationToken cancellationToken = default)
 | 
			
		||||
    {
 | 
			
		||||
        return this.ProcessQueryAsync(query, cancellationToken);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandlerBase.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandlerBase.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,92 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
using PoweredSoft.DynamicQuery;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery;
 | 
			
		||||
 | 
			
		||||
public abstract class DynamicQueryHandlerBase<TSource, TDestination>
 | 
			
		||||
    where TSource : class
 | 
			
		||||
    where TDestination : class
 | 
			
		||||
{
 | 
			
		||||
    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)
 | 
			
		||||
    {
 | 
			
		||||
        _queryHandlerAsync = queryHandlerAsync;
 | 
			
		||||
        _queryableProviders = queryableProviders;
 | 
			
		||||
        _alterQueryableServices = alterQueryableServices;
 | 
			
		||||
        _dynamicQueryInterceptorProviders = dynamicQueryInterceptorProviders;
 | 
			
		||||
        _serviceProvider = serviceProvider;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual Task<IQueryable<TSource>> GetQueryableAsync(IDynamicQuery query, CancellationToken cancellationToken = default)
 | 
			
		||||
    {
 | 
			
		||||
        if (_queryableProviders.Any())
 | 
			
		||||
            return _queryableProviders.ElementAt(0).GetQueryableAsync(query, cancellationToken);
 | 
			
		||||
 | 
			
		||||
        throw new Exception($"You must provide a QueryableProvider<TSource> for {typeof(TSource).Name}");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public virtual IQueryExecutionOptions GetQueryExecutionOptions(IQueryable<TSource> source, IDynamicQuery query)
 | 
			
		||||
    {
 | 
			
		||||
        return new QueryExecutionOptions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public virtual IEnumerable<IQueryInterceptor> GetInterceptors()
 | 
			
		||||
    {
 | 
			
		||||
        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)
 | 
			
		||||
    {
 | 
			
		||||
        var source = await GetQueryableAsync(query, cancellationToken);
 | 
			
		||||
        source = await AlterSourceAsync(source, query, cancellationToken);
 | 
			
		||||
        var options = GetQueryExecutionOptions(source, query);
 | 
			
		||||
        var interceptors = GetInterceptors();
 | 
			
		||||
 | 
			
		||||
        foreach (var interceptor in interceptors)
 | 
			
		||||
            _queryHandlerAsync.AddInterceptor(interceptor);
 | 
			
		||||
 | 
			
		||||
        var criteria = CreateCriteriaFromQuery(query);
 | 
			
		||||
        var result = await _queryHandlerAsync.ExecuteAsync<TSource, TDestination>(source, criteria, options, cancellationToken);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual async Task<IQueryable<TSource>> AlterSourceAsync(IQueryable<TSource> source, IDynamicQuery query, CancellationToken cancellationToken)
 | 
			
		||||
    {
 | 
			
		||||
        foreach (var t in _alterQueryableServices)
 | 
			
		||||
            source = await t.AlterQueryableAsync(source, query, cancellationToken);
 | 
			
		||||
 | 
			
		||||
        return source;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual IQueryCriteria CreateCriteriaFromQuery(IDynamicQuery query)
 | 
			
		||||
    {
 | 
			
		||||
        var criteria = new QueryCriteria
 | 
			
		||||
        {
 | 
			
		||||
            Page = query?.GetPage(),
 | 
			
		||||
            PageSize = query?.GetPageSize(),
 | 
			
		||||
            Filters = query?.GetFilters() ?? new List<IFilter>(),
 | 
			
		||||
            Sorts = query?.GetSorts() ?? new List<ISort>(),
 | 
			
		||||
            Groups = query?.GetGroups() ?? new List<IGroup>(),
 | 
			
		||||
            Aggregates = query?.GetAggregates() ?? new List<IAggregate>()
 | 
			
		||||
        };
 | 
			
		||||
        return criteria;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,18 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>netstandard2.1</TargetFramework>
 | 
			
		||||
    <PackageIconUrl>https://avatars.githubusercontent.com/u/52874619?v=4</PackageIconUrl>
 | 
			
		||||
    <Authors>David Lebee, Mathias Beaulieu-Duncan</Authors>
 | 
			
		||||
    <LangVersion>default</LangVersion>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Pluralize.NET" Version="1.0.2" />
 | 
			
		||||
    <PackageReference Include="PoweredSoft.DynamicQuery" Version="3.0.1" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS.DynamicQuery.Abstractions\OpenHarbor.CQRS.DynamicQuery.Abstractions.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS\OpenHarbor.CQRS.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										175
									
								
								OpenHarbor.CQRS.DynamicQuery/ServiceCollectionExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								OpenHarbor.CQRS.DynamicQuery/ServiceCollectionExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,175 @@
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection.Extensions;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
using OpenHarbor.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
using OpenHarbor.CQRS.DynamicQuery.Discover;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.DynamicQuery;
 | 
			
		||||
 | 
			
		||||
public static class ServiceCollectionExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static IServiceCollection AddDynamicQuery<TSourceAndDestination>(this IServiceCollection services, string name = null)
 | 
			
		||||
        where TSourceAndDestination : class
 | 
			
		||||
        => AddDynamicQuery<TSourceAndDestination, TSourceAndDestination>(services, name: name);
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddDynamicQuery<TSource, TDestination>(this IServiceCollection services, string name = null)
 | 
			
		||||
        where TSource : class
 | 
			
		||||
        where TDestination : class
 | 
			
		||||
    {
 | 
			
		||||
        // add query handler.
 | 
			
		||||
        services.AddTransient<IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination>>();
 | 
			
		||||
 | 
			
		||||
        // add for discovery purposes.
 | 
			
		||||
        var queryType = typeof(IDynamicQuery<TSource, TDestination>);
 | 
			
		||||
        var resultType = typeof(IQueryExecutionResult<TDestination>);
 | 
			
		||||
        var serviceType = typeof(DynamicQueryHandler<TSource, TDestination>);
 | 
			
		||||
        var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType)
 | 
			
		||||
        {
 | 
			
		||||
            OverridableName = name
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        services.AddSingleton<IQueryMeta>(queryMeta);
 | 
			
		||||
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddDynamicQueryWithProvider<TSource, TQueryableProvider>(this IServiceCollection services, string name = null)
 | 
			
		||||
        where TQueryableProvider : class, IQueryableProvider<TSource>
 | 
			
		||||
        where TSource : class
 | 
			
		||||
    {
 | 
			
		||||
        services.AddTransient<IQueryableProvider<TSource>, TQueryableProvider>()
 | 
			
		||||
            .AddDynamicQuery<TSource>(name: name);
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddDynamicQueryWithParamsAndProvider<TSource, TParams, TQueryableProvider>(this IServiceCollection services, string name = null)
 | 
			
		||||
        where TQueryableProvider : class, IQueryableProvider<TSource>
 | 
			
		||||
        where TParams : class
 | 
			
		||||
        where TSource : class
 | 
			
		||||
    {
 | 
			
		||||
        services.AddTransient<IQueryableProvider<TSource>, TQueryableProvider>()
 | 
			
		||||
            .AddDynamicQueryWithParams<TSource, TParams>(name: name);
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddDynamicQueryWithParams<TSourceAndDestination, TParams>(this IServiceCollection services, string name = null)
 | 
			
		||||
        where TSourceAndDestination : class
 | 
			
		||||
        where TParams : class
 | 
			
		||||
        => AddDynamicQueryWithParams<TSourceAndDestination, TSourceAndDestination, TParams>(services, name: name);
 | 
			
		||||
 | 
			
		||||
        public static IServiceCollection AddDynamicQueryWithParams<TSource, TDestination, TParams>(this IServiceCollection services, string name = null)
 | 
			
		||||
        where TSource : class
 | 
			
		||||
        where TDestination : class
 | 
			
		||||
        where TParams : class
 | 
			
		||||
    {
 | 
			
		||||
        // add query handler.
 | 
			
		||||
        services.AddTransient<IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination, TParams>>();
 | 
			
		||||
 | 
			
		||||
        // add for discovery purposes.
 | 
			
		||||
        var queryType = typeof(IDynamicQuery<TSource, TDestination, TParams>);
 | 
			
		||||
        var resultType = typeof(IQueryExecutionResult<TDestination>);
 | 
			
		||||
        var serviceType = typeof(DynamicQueryHandler<TSource, TDestination>);
 | 
			
		||||
        var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            // params type.
 | 
			
		||||
            ParamsType = typeof(TParams),
 | 
			
		||||
            OverridableName = name
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        services.AddSingleton<IQueryMeta>(queryMeta);
 | 
			
		||||
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddAlterQueryable<TSourceAndDestination, TService>(this IServiceCollection services)
 | 
			
		||||
        where TService : class, IAlterQueryableService<TSourceAndDestination, TSourceAndDestination>
 | 
			
		||||
    {
 | 
			
		||||
        return services.AddTransient<IAlterQueryableService<TSourceAndDestination, TSourceAndDestination>, TService>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddAlterQueryable<TSource, TDestination, TService>(this IServiceCollection services)
 | 
			
		||||
        where TService : class, IAlterQueryableService<TSource, TDestination>
 | 
			
		||||
    {
 | 
			
		||||
        return services.AddTransient<IAlterQueryableService<TSource, TDestination>, TService>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddAlterQueryableWithParams<TSourceAndTDestination, TParams, TService>
 | 
			
		||||
        (this IServiceCollection services)
 | 
			
		||||
        where TParams : class
 | 
			
		||||
        where TService : class, IAlterQueryableService<TSourceAndTDestination, TSourceAndTDestination, TParams>
 | 
			
		||||
    {
 | 
			
		||||
        return services.AddTransient<IAlterQueryableService< TSourceAndTDestination, TSourceAndTDestination, TParams>, TService>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddAlterQueryableWithParams<TSource, TDestination, TParams, TService>
 | 
			
		||||
        (this IServiceCollection services)
 | 
			
		||||
        where TParams : class
 | 
			
		||||
        where TService : class, IAlterQueryableService<TSource, TDestination, TParams>
 | 
			
		||||
    {
 | 
			
		||||
        return services.AddTransient<IAlterQueryableService<TSource, TDestination, TParams>, TService>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddDynamicQueryInterceptor<TSource, TDestination, TInterceptor>(this IServiceCollection services)
 | 
			
		||||
        where TInterceptor : class, IQueryInterceptor
 | 
			
		||||
    {
 | 
			
		||||
        services.TryAddTransient<TInterceptor>();
 | 
			
		||||
        return services.AddSingleton<IDynamicQueryInterceptorProvider<TSource, TDestination>>(
 | 
			
		||||
            new DynamicQueryInterceptorProvider<TSource, TDestination>(typeof(TInterceptor)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddDynamicQueryInterceptors<TSource, TDestination, T1, T2>(this IServiceCollection services)
 | 
			
		||||
        where T1 : class, IQueryInterceptor
 | 
			
		||||
        where T2 : class, IQueryInterceptor
 | 
			
		||||
    {
 | 
			
		||||
        services.TryAddTransient<T1>();
 | 
			
		||||
        services.TryAddTransient<T2>();
 | 
			
		||||
        return services.AddSingleton<IDynamicQueryInterceptorProvider<TSource, TDestination>>(
 | 
			
		||||
            new DynamicQueryInterceptorProvider<TSource, TDestination>(typeof(T1), typeof(T2)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddDynamicQueryInterceptors<TSource, TDestination, T1, T2, T3>(this IServiceCollection services)
 | 
			
		||||
        where T1 : class, IQueryInterceptor
 | 
			
		||||
        where T2 : class, IQueryInterceptor
 | 
			
		||||
        where T3 : class, IQueryInterceptor
 | 
			
		||||
    {
 | 
			
		||||
        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)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,16 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>netstandard2.1</TargetFramework>
 | 
			
		||||
    <PackageIconUrl>https://avatars.githubusercontent.com/u/52874619?v=4</PackageIconUrl>
 | 
			
		||||
    <Authors>David Lebee, Mathias Beaulieu-Duncan</Authors>
 | 
			
		||||
    <LangVersion>default</LangVersion>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="FluentValidation" Version="10.4.0" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS\OpenHarbor.CQRS.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@ -0,0 +1,43 @@
 | 
			
		||||
using FluentValidation;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.FluentValidation;
 | 
			
		||||
 | 
			
		||||
public static class ServiceCollectionExtensions
 | 
			
		||||
{
 | 
			
		||||
    private static IServiceCollection AddFluentValidator<T, TValidator>(this IServiceCollection services)
 | 
			
		||||
        where TValidator : class, IValidator<T>
 | 
			
		||||
    {
 | 
			
		||||
        services.AddTransient<IValidator<T>, TValidator>();
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddCommand<TCommand, TCommandHandler, TValidator>(this IServiceCollection services)
 | 
			
		||||
        where TCommand : class
 | 
			
		||||
        where TCommandHandler : class, ICommandHandler<TCommand>
 | 
			
		||||
        where TValidator : class, IValidator<TCommand>
 | 
			
		||||
    {
 | 
			
		||||
        return services.AddCommand<TCommand, TCommandHandler>()
 | 
			
		||||
            .AddFluentValidator<TCommand, TValidator>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddCommand<TCommand, TCommandResult, TCommandHandler, TValidator>(this IServiceCollection services)
 | 
			
		||||
        where TCommand : class
 | 
			
		||||
        where TCommandHandler : class, ICommandHandler<TCommand, TCommandResult>
 | 
			
		||||
        where TValidator : class, IValidator<TCommand>
 | 
			
		||||
    {
 | 
			
		||||
        return services.AddCommand<TCommand, TCommandResult, TCommandHandler>()
 | 
			
		||||
           .AddFluentValidator<TCommand, TValidator>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddQuery<TQuery, TQueryResult, TQueryHandler, TValidator>(this IServiceCollection services)
 | 
			
		||||
        where TQuery : class
 | 
			
		||||
        where TQueryHandler : class, IQueryHandler<TQuery, TQueryResult>
 | 
			
		||||
        where TValidator : class, IValidator<TQuery>
 | 
			
		||||
    {
 | 
			
		||||
        services.AddQuery<TQuery, TQueryResult, TQueryHandler>()
 | 
			
		||||
                .AddFluentValidator<TQuery, TValidator>();
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 | 
			
		||||
# Visual Studio Version 16
 | 
			
		||||
VisualStudioVersion = 16.0.30907.101
 | 
			
		||||
MinimumVisualStudioVersion = 10.0.40219.1
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.CQRS.Abstractions", "PoweredSoft.CQRS.Abstractions\PoweredSoft.CQRS.Abstractions.csproj", "{ED78E19D-31D4-4783-AE9E-2844A8541277}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenHarbor.CQRS.Abstractions", "OpenHarbor.CQRS.Abstractions\OpenHarbor.CQRS.Abstractions.csproj", "{ED78E19D-31D4-4783-AE9E-2844A8541277}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.CQRS", "PoweredSoft.CQRS\PoweredSoft.CQRS.csproj", "{7069B98F-8736-4114-8AF5-1ACE094E6238}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenHarbor.CQRS", "OpenHarbor.CQRS\OpenHarbor.CQRS.csproj", "{7069B98F-8736-4114-8AF5-1ACE094E6238}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.CQRS.AspNetCore", "PoweredSoft.CQRS.AspNetCore\PoweredSoft.CQRS.AspNetCore.csproj", "{A1D577E5-61BD-4E25-B2C8-1005C1D7665B}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenHarbor.CQRS.AspNetCore", "OpenHarbor.CQRS.AspNetCore\OpenHarbor.CQRS.AspNetCore.csproj", "{A1D577E5-61BD-4E25-B2C8-1005C1D7665B}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.CQRS.AspNetCore.Abstractions", "PoweredSoft.CQRS.AspNetCore.Abstractions\PoweredSoft.CQRS.AspNetCore.Abstractions.csproj", "{4C466827-31D3-4081-A751-C2FC7C381D7E}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenHarbor.CQRS.AspNetCore.Abstractions", "OpenHarbor.CQRS.AspNetCore.Abstractions\OpenHarbor.CQRS.AspNetCore.Abstractions.csproj", "{4C466827-31D3-4081-A751-C2FC7C381D7E}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{617BA357-1A1F-40C5-B19A-A65A960E6142}"
 | 
			
		||||
	ProjectSection(SolutionItems) = preProject
 | 
			
		||||
@ -17,13 +17,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 | 
			
		||||
		README.md = README.md
 | 
			
		||||
	EndProjectSection
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.CQRS.DynamicQuery", "PoweredSoft.CQRS.DynamicQuery\PoweredSoft.CQRS.DynamicQuery.csproj", "{A38CE930-191F-417C-B5BE-8CC62DB47513}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenHarbor.CQRS.DynamicQuery", "OpenHarbor.CQRS.DynamicQuery\OpenHarbor.CQRS.DynamicQuery.csproj", "{A38CE930-191F-417C-B5BE-8CC62DB47513}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.CQRS.DynamicQuery.Abstractions", "PoweredSoft.CQRS.DynamicQuery.Abstractions\PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj", "{60B5E255-77B8-48E0-AE8F-04E8332970F9}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenHarbor.CQRS.DynamicQuery.AspNetCore", "OpenHarbor.CQRS.DynamicQuery.AspNetCore\OpenHarbor.CQRS.DynamicQuery.AspNetCore.csproj", "{0829B99A-0A20-4CAC-A91E-FB67E18444DE}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.CQRS.DynamicQuery.AspNetCore", "PoweredSoft.CQRS.DynamicQuery.AspNetCore\PoweredSoft.CQRS.DynamicQuery.AspNetCore.csproj", "{0829B99A-0A20-4CAC-A91E-FB67E18444DE}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenHarbor.CQRS.FluentValidation", "OpenHarbor.CQRS.FluentValidation\OpenHarbor.CQRS.FluentValidation.csproj", "{70BD37C4-7497-474D-9A40-A701203971D8}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PoweredSoft.CQRS.FluentValidation", "PoweredSoft.CQRS.FluentValidation\PoweredSoft.CQRS.FluentValidation.csproj", "{70BD37C4-7497-474D-9A40-A701203971D8}"
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenHarbor.CQRS.DynamicQuery.Abstractions", "OpenHarbor.CQRS.DynamicQuery.Abstractions\OpenHarbor.CQRS.DynamicQuery.Abstractions.csproj", "{8B9F8ACE-10EA-4215-9776-DE29EC93B020}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
@ -51,10 +51,6 @@ Global
 | 
			
		||||
		{A38CE930-191F-417C-B5BE-8CC62DB47513}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{A38CE930-191F-417C-B5BE-8CC62DB47513}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{A38CE930-191F-417C-B5BE-8CC62DB47513}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{60B5E255-77B8-48E0-AE8F-04E8332970F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{60B5E255-77B8-48E0-AE8F-04E8332970F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{60B5E255-77B8-48E0-AE8F-04E8332970F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{60B5E255-77B8-48E0-AE8F-04E8332970F9}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{0829B99A-0A20-4CAC-A91E-FB67E18444DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{0829B99A-0A20-4CAC-A91E-FB67E18444DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{0829B99A-0A20-4CAC-A91E-FB67E18444DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
@ -63,6 +59,10 @@ Global
 | 
			
		||||
		{70BD37C4-7497-474D-9A40-A701203971D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{70BD37C4-7497-474D-9A40-A701203971D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{70BD37C4-7497-474D-9A40-A701203971D8}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{8B9F8ACE-10EA-4215-9776-DE29EC93B020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{8B9F8ACE-10EA-4215-9776-DE29EC93B020}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{8B9F8ACE-10EA-4215-9776-DE29EC93B020}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{8B9F8ACE-10EA-4215-9776-DE29EC93B020}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
							
								
								
									
										22
									
								
								OpenHarbor.CQRS/Discovery/CommandDiscovery.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								OpenHarbor.CQRS/Discovery/CommandDiscovery.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Discovery;
 | 
			
		||||
 | 
			
		||||
public sealed class CommandDiscovery : ICommandDiscovery
 | 
			
		||||
{
 | 
			
		||||
    private readonly IEnumerable<ICommandMeta> _commandMetas;
 | 
			
		||||
 | 
			
		||||
    public CommandDiscovery(IEnumerable<ICommandMeta> commandMetas)
 | 
			
		||||
    {
 | 
			
		||||
        _commandMetas = commandMetas;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IEnumerable<ICommandMeta> GetCommands() => _commandMetas;
 | 
			
		||||
    public ICommandMeta FindCommand(string name) => _commandMetas.FirstOrDefault(t => t.Name == name);
 | 
			
		||||
    public ICommandMeta FindCommand(Type commandType) => _commandMetas.FirstOrDefault(t => t.CommandType == commandType);
 | 
			
		||||
    public bool CommandExists(string name) => _commandMetas.Any(t => t.Name == name);
 | 
			
		||||
    public bool CommandExists(Type commandType) => _commandMetas.Any(t => t.CommandType == commandType);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								OpenHarbor.CQRS/Discovery/QueryDiscovery.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								OpenHarbor.CQRS/Discovery/QueryDiscovery.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS.Discovery;
 | 
			
		||||
 | 
			
		||||
public sealed class QueryDiscovery : IQueryDiscovery
 | 
			
		||||
{
 | 
			
		||||
    private readonly IEnumerable<IQueryMeta> _queryMetas;
 | 
			
		||||
 | 
			
		||||
    public QueryDiscovery(IEnumerable<IQueryMeta> queryMetas)
 | 
			
		||||
    {
 | 
			
		||||
        _queryMetas = queryMetas;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public IEnumerable<IQueryMeta> GetQueries() => _queryMetas;
 | 
			
		||||
    public IQueryMeta FindQuery(string name) => _queryMetas.FirstOrDefault(t => t.Name == name);
 | 
			
		||||
    public IQueryMeta FindQuery(Type queryType) => _queryMetas.FirstOrDefault(t => t.QueryType == queryType);
 | 
			
		||||
    public bool QueryExists(string name) => _queryMetas.Any(t => t.Name == name);
 | 
			
		||||
    public bool QueryExists(Type queryType) => _queryMetas.Any(t => t.QueryType == queryType);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								OpenHarbor.CQRS/OpenHarbor.CQRS.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								OpenHarbor.CQRS/OpenHarbor.CQRS.csproj
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>netstandard2.1</TargetFramework>
 | 
			
		||||
    <PackageIconUrl>https://avatars.githubusercontent.com/u/52874619?v=4</PackageIconUrl>
 | 
			
		||||
    <Authors>David Lebee, Mathias Beaulieu-Duncan</Authors>
 | 
			
		||||
    <LangVersion>default</LangVersion>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\OpenHarbor.CQRS.Abstractions\OpenHarbor.CQRS.Abstractions.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										21
									
								
								OpenHarbor.CQRS/ServiceCollectionExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								OpenHarbor.CQRS/ServiceCollectionExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection.Extensions;
 | 
			
		||||
using OpenHarbor.CQRS.Abstractions.Discovery;
 | 
			
		||||
using OpenHarbor.CQRS.Discovery;
 | 
			
		||||
 | 
			
		||||
namespace OpenHarbor.CQRS;
 | 
			
		||||
 | 
			
		||||
public static class ServiceCollectionExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static IServiceCollection AddDefaultQueryDiscovery(this IServiceCollection services)
 | 
			
		||||
    {
 | 
			
		||||
        services.TryAddTransient<IQueryDiscovery, QueryDiscovery>();
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IServiceCollection AddDefaultCommandDiscovery(this IServiceCollection services)
 | 
			
		||||
    {
 | 
			
		||||
        services.TryAddTransient<ICommandDiscovery, CommandDiscovery>();
 | 
			
		||||
        return services;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,15 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Attributes
 | 
			
		||||
{
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
 | 
			
		||||
    public class CommandNameAttribute : Attribute
 | 
			
		||||
    {
 | 
			
		||||
        public CommandNameAttribute(string name)
 | 
			
		||||
        {
 | 
			
		||||
            Name = name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string Name { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,15 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Attributes
 | 
			
		||||
{
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
 | 
			
		||||
    public class QueryNameAttribute : Attribute
 | 
			
		||||
    {
 | 
			
		||||
        public QueryNameAttribute(string name)
 | 
			
		||||
        {
 | 
			
		||||
            Name = name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string Name { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,51 +0,0 @@
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions.Attributes;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Discovery
 | 
			
		||||
{
 | 
			
		||||
    public class CommandMeta : ICommandMeta
 | 
			
		||||
    {
 | 
			
		||||
        public CommandMeta(Type commandType, Type serviceType, Type commandResultType)
 | 
			
		||||
        {
 | 
			
		||||
            CommandType = commandType;
 | 
			
		||||
            ServiceType = serviceType;
 | 
			
		||||
            CommandResultType = commandResultType;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CommandMeta(Type commandType, Type serviceType)
 | 
			
		||||
        {
 | 
			
		||||
            CommandType = commandType;
 | 
			
		||||
            ServiceType = serviceType;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected virtual CommandNameAttribute NameAttribute => CommandType.GetCustomAttribute<CommandNameAttribute>();
 | 
			
		||||
 | 
			
		||||
        public virtual string Name
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                var name = NameAttribute?.Name ?? CommandType.Name.Replace("Command", string.Empty);
 | 
			
		||||
                return name;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public virtual Type CommandType { get; }
 | 
			
		||||
        public virtual Type ServiceType { get; }
 | 
			
		||||
        public virtual Type CommandResultType { get; }
 | 
			
		||||
 | 
			
		||||
        public string LowerCamelCaseName
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrEmpty(Name))
 | 
			
		||||
                    return Name;
 | 
			
		||||
 | 
			
		||||
                var name = Name;
 | 
			
		||||
                var firstLetter = Char.ToLowerInvariant(name[0]);
 | 
			
		||||
                var ret = $"{firstLetter}{name.Substring(1)}";
 | 
			
		||||
                return ret;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,13 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Discovery
 | 
			
		||||
{
 | 
			
		||||
    public interface ICommandMeta
 | 
			
		||||
    {
 | 
			
		||||
        string Name { get; }
 | 
			
		||||
        Type CommandType { get; }
 | 
			
		||||
        Type ServiceType { get; }
 | 
			
		||||
        Type CommandResultType { get; }
 | 
			
		||||
        string LowerCamelCaseName { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,23 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Discovery
 | 
			
		||||
{
 | 
			
		||||
    public interface IQueryDiscovery
 | 
			
		||||
    {
 | 
			
		||||
        IQueryMeta FindQuery(string name);
 | 
			
		||||
        IQueryMeta FindQuery(Type queryType);
 | 
			
		||||
        IEnumerable<IQueryMeta> GetQueries();
 | 
			
		||||
        bool QueryExists(string name);
 | 
			
		||||
        bool QueryExists(Type queryType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface ICommandDiscovery
 | 
			
		||||
    {
 | 
			
		||||
        bool CommandExists(string name);
 | 
			
		||||
        bool CommandExists(Type commandType);
 | 
			
		||||
        ICommandMeta FindCommand(string name);
 | 
			
		||||
        ICommandMeta FindCommand(Type commandType);
 | 
			
		||||
        IEnumerable<ICommandMeta> GetCommands();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,14 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Discovery
 | 
			
		||||
{
 | 
			
		||||
    public interface IQueryMeta
 | 
			
		||||
    {
 | 
			
		||||
        string Name { get; }
 | 
			
		||||
        Type QueryType { get; }
 | 
			
		||||
        Type ServiceType { get; }
 | 
			
		||||
        Type QueryResultType { get; }
 | 
			
		||||
        string Category { get; }
 | 
			
		||||
        string LowerCamelCaseName { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,46 +0,0 @@
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions.Attributes;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Discovery
 | 
			
		||||
{
 | 
			
		||||
    public class QueryMeta : IQueryMeta
 | 
			
		||||
    {
 | 
			
		||||
        public QueryMeta(Type queryType, Type serviceType, Type queryResultType)
 | 
			
		||||
        {
 | 
			
		||||
            QueryType = queryType;
 | 
			
		||||
            ServiceType = serviceType;
 | 
			
		||||
            QueryResultType = queryResultType;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected virtual QueryNameAttribute NameAttribute => QueryType.GetCustomAttribute<QueryNameAttribute>();
 | 
			
		||||
 | 
			
		||||
        public virtual string Name
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                var name = NameAttribute?.Name ?? QueryType.Name.Replace("Query", string.Empty);
 | 
			
		||||
                return name;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public virtual Type QueryType { get; }
 | 
			
		||||
        public virtual Type ServiceType { get; }
 | 
			
		||||
        public virtual Type QueryResultType { get; }
 | 
			
		||||
        public virtual string Category => "BasicQuery";
 | 
			
		||||
 | 
			
		||||
        public string LowerCamelCaseName
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrEmpty(Name))
 | 
			
		||||
                    return Name;
 | 
			
		||||
 | 
			
		||||
                var name = Name;
 | 
			
		||||
                var firstLetter = Char.ToLowerInvariant(name[0]);
 | 
			
		||||
                var ret = $"{firstLetter}{name.Substring(1)}";
 | 
			
		||||
                return ret;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions
 | 
			
		||||
{
 | 
			
		||||
    public interface ICommandHandler<in TCommand>
 | 
			
		||||
        where TCommand : class
 | 
			
		||||
    {
 | 
			
		||||
        Task HandleAsync(TCommand command, CancellationToken cancellationToken = default);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface ICommandHandler<in TCommand, TCommandResult>
 | 
			
		||||
        where TCommand : class
 | 
			
		||||
    {
 | 
			
		||||
        Task<TCommandResult> HandleAsync(TCommand command, CancellationToken cancellationToken = default);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions
 | 
			
		||||
{
 | 
			
		||||
    public interface IQueryHandler<in TQuery, TQueryResult>
 | 
			
		||||
        where TQuery : class
 | 
			
		||||
    {
 | 
			
		||||
        Task<TQueryResult> HandleAsync(TQuery query, CancellationToken cancellationToken = default);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Security
 | 
			
		||||
{
 | 
			
		||||
    public enum AuthorizationResult
 | 
			
		||||
    {
 | 
			
		||||
        Unauthorized,
 | 
			
		||||
        Forbidden,
 | 
			
		||||
        Allowed
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Security
 | 
			
		||||
{
 | 
			
		||||
    public interface ICommandAuthorizationService
 | 
			
		||||
    {
 | 
			
		||||
        Task<AuthorizationResult> IsAllowedAsync(Type commandType, CancellationToken cancellationToken = default);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,12 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions.Security
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    public interface IQueryAuthorizationService
 | 
			
		||||
    {
 | 
			
		||||
        Task<AuthorizationResult> IsAllowedAsync(Type queryType, CancellationToken cancellationToken = default);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,50 +0,0 @@
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions.Discovery;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.Abstractions
 | 
			
		||||
{
 | 
			
		||||
    public static class ServiceCollectionExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static IServiceCollection AddQuery<TQuery, TQueryResult, TQueryHandler>(this IServiceCollection services)
 | 
			
		||||
            where TQuery : class
 | 
			
		||||
            where TQueryHandler : class, IQueryHandler<TQuery, TQueryResult>
 | 
			
		||||
        {
 | 
			
		||||
            // add handler to DI.
 | 
			
		||||
            services.AddTransient<IQueryHandler<TQuery, TQueryResult>, TQueryHandler>();
 | 
			
		||||
 | 
			
		||||
            // add for discovery purposes.
 | 
			
		||||
            var queryMeta = new QueryMeta(typeof(TQuery), typeof(IQueryHandler<TQuery, TQueryResult>), typeof(TQueryResult));
 | 
			
		||||
            services.AddSingleton<IQueryMeta>(queryMeta);
 | 
			
		||||
 | 
			
		||||
            return services;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IServiceCollection AddCommand<TCommand, TCommandResult, TCommandHandler>(this IServiceCollection services)
 | 
			
		||||
            where TCommand : class
 | 
			
		||||
            where TCommandHandler : class, ICommandHandler<TCommand, TCommandResult>
 | 
			
		||||
        {
 | 
			
		||||
            // add handler to DI.
 | 
			
		||||
            services.AddTransient<ICommandHandler<TCommand, TCommandResult>, TCommandHandler>();
 | 
			
		||||
 | 
			
		||||
            // add for discovery purposes.
 | 
			
		||||
            var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler<TCommand>), typeof(TCommandResult));
 | 
			
		||||
            services.AddSingleton<ICommandMeta>(commandMeta);
 | 
			
		||||
 | 
			
		||||
            return services;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IServiceCollection AddCommand<TCommand, TCommandHandler>(this IServiceCollection services)
 | 
			
		||||
            where TCommand : class
 | 
			
		||||
            where TCommandHandler : class, ICommandHandler<TCommand>
 | 
			
		||||
        {
 | 
			
		||||
            // add handler to DI.
 | 
			
		||||
            services.AddTransient<ICommandHandler<TCommand>, TCommandHandler>();
 | 
			
		||||
 | 
			
		||||
            // add for discovery purposes.
 | 
			
		||||
            var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler<TCommand>));
 | 
			
		||||
            services.AddSingleton<ICommandMeta>(commandMeta);
 | 
			
		||||
 | 
			
		||||
            return services;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Abstractions.Attributes
 | 
			
		||||
{
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
 | 
			
		||||
    public class CommandControllerIgnoreAttribute : Attribute
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Abstractions.Attributes
 | 
			
		||||
{
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
 | 
			
		||||
    public class QueryControllerIgnoreAttribute : Attribute
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>netstandard2.1</TargetFramework>
 | 
			
		||||
    <Copyright>Powered Softwares Inc.</Copyright>
 | 
			
		||||
    <PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro</PackageIconUrl>
 | 
			
		||||
    <Company>PoweredSoft</Company>
 | 
			
		||||
    <Authors>PoweredSoft Team</Authors>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@ -1,39 +0,0 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    [Produces("application/json")]
 | 
			
		||||
    [ApiController, Route("api/command/[controller]")]
 | 
			
		||||
    public class CommandController<TCommand> : Controller
 | 
			
		||||
        where TCommand : class
 | 
			
		||||
    {
 | 
			
		||||
        [HttpPost, CommandControllerAuthorization]
 | 
			
		||||
        public async Task<IActionResult> Handle([FromServices] ICommandHandler<TCommand> handler, 
 | 
			
		||||
            [FromBody] TCommand command)
 | 
			
		||||
        {
 | 
			
		||||
            if (!ModelState.IsValid)
 | 
			
		||||
                return BadRequest(ModelState);
 | 
			
		||||
 | 
			
		||||
            await handler.HandleAsync(command, this.Request.HttpContext.RequestAborted);
 | 
			
		||||
            return Ok();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Produces("application/json")]
 | 
			
		||||
    [ApiController, Route("api/command/[controller]")]
 | 
			
		||||
    public class CommandController<TCommand, TTCommandResult> : Controller
 | 
			
		||||
        where TCommand : class
 | 
			
		||||
    {
 | 
			
		||||
        [HttpPost, CommandControllerAuthorization]
 | 
			
		||||
        public async Task<ActionResult<TTCommandResult>> Handle([FromServices] ICommandHandler<TCommand, TTCommandResult> handler,
 | 
			
		||||
            [FromBody] TCommand command)
 | 
			
		||||
        {
 | 
			
		||||
            if (!ModelState.IsValid)
 | 
			
		||||
                return BadRequest(ModelState);
 | 
			
		||||
 | 
			
		||||
            return Ok(await handler.HandleAsync(command, this.Request.HttpContext.RequestAborted));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,44 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Filters;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions.Security;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    public class CommandControllerAsyncAuthorizationFilter : IAsyncAuthorizationFilter
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ICommandAuthorizationService authorizationService;
 | 
			
		||||
 | 
			
		||||
        public CommandControllerAsyncAuthorizationFilter(IServiceProvider serviceProvider)
 | 
			
		||||
        {
 | 
			
		||||
            authorizationService = serviceProvider.GetService<ICommandAuthorizationService>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
 | 
			
		||||
        {
 | 
			
		||||
            if (authorizationService == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var action = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
 | 
			
		||||
            if (action == null)
 | 
			
		||||
                throw new Exception("Only Supports controller action descriptor");
 | 
			
		||||
 | 
			
		||||
            var attribute = action.MethodInfo.GetCustomAttribute<CommandControllerAuthorizationAttribute>();
 | 
			
		||||
            Type commandType;
 | 
			
		||||
            if (attribute?.CommandType != null)
 | 
			
		||||
                commandType = attribute.CommandType;
 | 
			
		||||
            else
 | 
			
		||||
                commandType = action.ControllerTypeInfo.GenericTypeArguments.First();
 | 
			
		||||
 | 
			
		||||
            var ar = await authorizationService.IsAllowedAsync(commandType);
 | 
			
		||||
            if (ar == AuthorizationResult.Forbidden)
 | 
			
		||||
                context.Result = new StatusCodeResult(403);
 | 
			
		||||
            else if(ar == AuthorizationResult.Unauthorized)
 | 
			
		||||
                context.Result = new StatusCodeResult(401);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,21 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Method)]
 | 
			
		||||
    public class CommandControllerAuthorizationAttribute : TypeFilterAttribute
 | 
			
		||||
    {
 | 
			
		||||
        public CommandControllerAuthorizationAttribute() : base(typeof(CommandControllerAsyncAuthorizationFilter))
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CommandControllerAuthorizationAttribute(Type commandType) : base(typeof(CommandControllerAsyncAuthorizationFilter))
 | 
			
		||||
        {
 | 
			
		||||
            CommandType = commandType;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Type CommandType { get; } = null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,34 +0,0 @@
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions.Discovery;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    public class CommandControllerConvention : IControllerModelConvention
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IServiceProvider serviceProvider;
 | 
			
		||||
 | 
			
		||||
        public CommandControllerConvention(IServiceProvider serviceProvider)
 | 
			
		||||
        {
 | 
			
		||||
            this.serviceProvider = serviceProvider;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Apply(ControllerModel controller)
 | 
			
		||||
        {
 | 
			
		||||
            if (!controller.ControllerType.IsGenericType)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (!controller.ControllerType.Name.Contains("CommandController"))
 | 
			
		||||
                return;
 | 
			
		||||
            
 | 
			
		||||
            if (controller.ControllerType.Assembly != typeof(CommandControllerConvention).Assembly)
 | 
			
		||||
                return;
 | 
			
		||||
                
 | 
			
		||||
            var genericType = controller.ControllerType.GenericTypeArguments[0];
 | 
			
		||||
            var commandDiscovery = this.serviceProvider.GetRequiredService<ICommandDiscovery>();
 | 
			
		||||
            var command = commandDiscovery.FindCommand(genericType);
 | 
			
		||||
            controller.ControllerName = command.LowerCamelCaseName;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,44 +0,0 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Controllers;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions.Discovery;
 | 
			
		||||
using PoweredSoft.CQRS.AspNetCore.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    public class CommandControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ServiceProvider serviceProvider;
 | 
			
		||||
 | 
			
		||||
        public CommandControllerFeatureProvider(ServiceProvider serviceProvider)
 | 
			
		||||
        {
 | 
			
		||||
            this.serviceProvider = serviceProvider;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
 | 
			
		||||
        {
 | 
			
		||||
            var commandDiscovery = this.serviceProvider.GetRequiredService<ICommandDiscovery>();
 | 
			
		||||
            foreach (var f in commandDiscovery.GetCommands())
 | 
			
		||||
            {
 | 
			
		||||
                var ignoreAttribute = f.CommandType.GetCustomAttribute<CommandControllerIgnoreAttribute>();
 | 
			
		||||
                if (ignoreAttribute != null)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                if (f.CommandResultType == null)
 | 
			
		||||
                {
 | 
			
		||||
                    var controllerType = typeof(CommandController<>).MakeGenericType(f.CommandType);
 | 
			
		||||
                    var controllerTypeInfo = controllerType.GetTypeInfo();
 | 
			
		||||
                    feature.Controllers.Add(controllerTypeInfo);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    var controllerType = typeof(CommandController<,>).MakeGenericType(f.CommandType, f.CommandResultType);
 | 
			
		||||
                    var controllerTypeInfo = controllerType.GetTypeInfo();
 | 
			
		||||
                    feature.Controllers.Add(controllerTypeInfo);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    public class CommandControllerOptions
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,34 +0,0 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    [Produces("application/json")]
 | 
			
		||||
    [ApiController, Route("api/query/[controller]")]
 | 
			
		||||
    public class QueryController<TQuery, TQueryResult> : Controller
 | 
			
		||||
        where TQuery : class
 | 
			
		||||
    {
 | 
			
		||||
        [HttpPost, QueryControllerAuthorization]
 | 
			
		||||
        public async Task<ActionResult<TQueryResult>> Handle([FromServices] IQueryHandler<TQuery, TQueryResult> handler, 
 | 
			
		||||
            [FromBody] TQuery query)
 | 
			
		||||
        {
 | 
			
		||||
            if (!ModelState.IsValid)
 | 
			
		||||
                return BadRequest(ModelState);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            return Ok(await handler.HandleAsync(query, this.Request.HttpContext.RequestAborted));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [HttpGet, QueryControllerAuthorization]
 | 
			
		||||
        public async Task<ActionResult<TQueryResult>> HandleGet([FromServices] IQueryHandler<TQuery, TQueryResult> handler,
 | 
			
		||||
            [FromQuery] TQuery query)
 | 
			
		||||
        {
 | 
			
		||||
            if (!ModelState.IsValid)
 | 
			
		||||
                return BadRequest(ModelState);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            return Ok(await handler.HandleAsync(query, this.Request.HttpContext.RequestAborted));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,44 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Filters;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions.Security;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    public class QueryControllerAsyncAuthorizationFilter : IAsyncAuthorizationFilter
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IQueryAuthorizationService authorizationService;
 | 
			
		||||
 | 
			
		||||
        public QueryControllerAsyncAuthorizationFilter(IServiceProvider serviceProvider)
 | 
			
		||||
        {
 | 
			
		||||
            authorizationService = serviceProvider.GetService<IQueryAuthorizationService>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
 | 
			
		||||
        {
 | 
			
		||||
            if (authorizationService == null)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var action = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
 | 
			
		||||
            if (action == null)
 | 
			
		||||
                throw new Exception("Only Supports controller action descriptor");
 | 
			
		||||
 | 
			
		||||
            var attribute = action.MethodInfo.GetCustomAttribute<QueryControllerAuthorizationAttribute>();
 | 
			
		||||
            Type queryType;
 | 
			
		||||
            if (attribute?.QueryType != null)
 | 
			
		||||
                queryType = attribute.QueryType;
 | 
			
		||||
            else
 | 
			
		||||
                queryType = action.ControllerTypeInfo.GenericTypeArguments.First();
 | 
			
		||||
 | 
			
		||||
            var ar = await authorizationService.IsAllowedAsync(queryType);
 | 
			
		||||
            if (ar == AuthorizationResult.Forbidden)
 | 
			
		||||
                context.Result = new StatusCodeResult(403);
 | 
			
		||||
            else if (ar == AuthorizationResult.Unauthorized)
 | 
			
		||||
                context.Result = new StatusCodeResult(401);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,21 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    [AttributeUsage(AttributeTargets.Method)]
 | 
			
		||||
    public class QueryControllerAuthorizationAttribute : TypeFilterAttribute
 | 
			
		||||
    {
 | 
			
		||||
        public QueryControllerAuthorizationAttribute() : base(typeof(QueryControllerAsyncAuthorizationFilter))
 | 
			
		||||
        {
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public QueryControllerAuthorizationAttribute(Type queryType) : base(typeof(QueryControllerAsyncAuthorizationFilter))
 | 
			
		||||
        {
 | 
			
		||||
            QueryType = queryType;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Type QueryType { get; } = null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,28 +0,0 @@
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions.Discovery;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    public class QueryControllerConvention : IControllerModelConvention
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IServiceProvider serviceProvider;
 | 
			
		||||
 | 
			
		||||
        public QueryControllerConvention(IServiceProvider serviceProvider)
 | 
			
		||||
        {
 | 
			
		||||
            this.serviceProvider = serviceProvider;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Apply(ControllerModel controller)
 | 
			
		||||
        {
 | 
			
		||||
            if (controller.ControllerType.IsGenericType && controller.ControllerType.Name.Contains("QueryController") && controller.ControllerType.Assembly == typeof(QueryControllerConvention).Assembly)
 | 
			
		||||
            {
 | 
			
		||||
                var genericType = controller.ControllerType.GenericTypeArguments[0];
 | 
			
		||||
                var queryDiscovery = this.serviceProvider.GetRequiredService<IQueryDiscovery>();
 | 
			
		||||
                var query = queryDiscovery.FindQuery(genericType);
 | 
			
		||||
                controller.ControllerName = query.LowerCamelCaseName;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,38 +0,0 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Controllers;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions.Discovery;
 | 
			
		||||
using PoweredSoft.CQRS.AspNetCore.Abstractions.Attributes;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    public class QueryControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ServiceProvider serviceProvider;
 | 
			
		||||
 | 
			
		||||
        public QueryControllerFeatureProvider(ServiceProvider serviceProvider)
 | 
			
		||||
        {
 | 
			
		||||
            this.serviceProvider = serviceProvider;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
 | 
			
		||||
        {
 | 
			
		||||
            var queryDiscovery = this.serviceProvider.GetRequiredService<IQueryDiscovery>();
 | 
			
		||||
            foreach (var f in queryDiscovery.GetQueries())
 | 
			
		||||
            {
 | 
			
		||||
                var ignoreAttribute = f.QueryType.GetCustomAttribute<QueryControllerIgnoreAttribute>();
 | 
			
		||||
                if (ignoreAttribute != null)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                if (f.Category != "BasicQuery")
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                var controllerType = typeof(QueryController<,>).MakeGenericType(f.QueryType, f.QueryResultType);
 | 
			
		||||
                var controllerTypeInfo = controllerType.GetTypeInfo();
 | 
			
		||||
                feature.Controllers.Add(controllerTypeInfo);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    public class QueryControllerOptions
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,29 +0,0 @@
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    public static class MvcBuilderExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static IMvcBuilder AddPoweredSoftQueries(this IMvcBuilder builder, Action<QueryControllerOptions> configuration = null)
 | 
			
		||||
        {
 | 
			
		||||
            var options = new QueryControllerOptions();
 | 
			
		||||
            configuration?.Invoke(options);
 | 
			
		||||
            var services = builder.Services;
 | 
			
		||||
            var serviceProvider = services.BuildServiceProvider();
 | 
			
		||||
            builder.AddMvcOptions(o => o.Conventions.Add(new QueryControllerConvention(serviceProvider)));
 | 
			
		||||
            builder.ConfigureApplicationPartManager(m => m.FeatureProviders.Add(new QueryControllerFeatureProvider(serviceProvider)));
 | 
			
		||||
            return builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IMvcBuilder AddPoweredSoftCommands(this IMvcBuilder builder)
 | 
			
		||||
        {
 | 
			
		||||
            var services = builder.Services;
 | 
			
		||||
            var serviceProvider = services.BuildServiceProvider();
 | 
			
		||||
            builder.AddMvcOptions(o => o.Conventions.Add(new CommandControllerConvention(serviceProvider)));
 | 
			
		||||
            builder.ConfigureApplicationPartManager(m => m.FeatureProviders.Add(new CommandControllerFeatureProvider(serviceProvider)));
 | 
			
		||||
            return builder;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,21 +0,0 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>net8.0</TargetFramework>
 | 
			
		||||
    <Copyright>Powered Softwares Inc.</Copyright>
 | 
			
		||||
    <PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro</PackageIconUrl>
 | 
			
		||||
    <Company>PoweredSoft</Company>
 | 
			
		||||
    <Authors>PoweredSoft Team</Authors>
 | 
			
		||||
    <IsAotCompatible>true</IsAotCompatible>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\PoweredSoft.CQRS.Abstractions\PoweredSoft.CQRS.Abstractions.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\PoweredSoft.CQRS.AspNetCore.Abstractions\PoweredSoft.CQRS.AspNetCore.Abstractions.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
 | 
			
		||||
{
 | 
			
		||||
    public interface IAlterQueryableService<TSource, TDestination>
 | 
			
		||||
    {
 | 
			
		||||
        Task<IQueryable<TSource>> AlterQueryableAsync(IQueryable<TSource> query, IDynamicQuery dynamicQuery, CancellationToken cancellationToken = default);
 | 
			
		||||
    }
 | 
			
		||||
    public interface IAlterQueryableService<TSource, TDestination, TParams>
 | 
			
		||||
        where TParams : class
 | 
			
		||||
    {
 | 
			
		||||
        Task<IQueryable<TSource>> AlterQueryableAsync(IQueryable<TSource> query, IDynamicQueryParams<TParams> dynamicQuery, CancellationToken cancellationToken = default);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,30 +0,0 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
 | 
			
		||||
{
 | 
			
		||||
    public interface IDynamicQuery<TSource, TDestination> : IDynamicQuery
 | 
			
		||||
        where TSource : class
 | 
			
		||||
        where TDestination : class
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface IDynamicQuery<TSource, TDestination, out TParams> : IDynamicQuery<TSource, TDestination>, IDynamicQueryParams<TParams>
 | 
			
		||||
        where TSource : class
 | 
			
		||||
        where TDestination : class
 | 
			
		||||
        where TParams : class
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface IDynamicQuery
 | 
			
		||||
    {
 | 
			
		||||
        List<IFilter> GetFilters();
 | 
			
		||||
        List<IGroup> GetGroups();
 | 
			
		||||
        List<ISort> GetSorts();
 | 
			
		||||
        List<IAggregate> GetAggregates();
 | 
			
		||||
        int? GetPage();
 | 
			
		||||
        int? GetPageSize();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
 | 
			
		||||
{
 | 
			
		||||
    public interface IDynamicQueryInterceptorProvider<TSource, TDestination>
 | 
			
		||||
    {
 | 
			
		||||
        IEnumerable<Type> GetInterceptorsTypes();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +0,0 @@
 | 
			
		||||
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
 | 
			
		||||
{
 | 
			
		||||
    public interface IDynamicQueryParams<out TParams>
 | 
			
		||||
        where TParams : class
 | 
			
		||||
    {
 | 
			
		||||
        TParams GetParams();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
 | 
			
		||||
{
 | 
			
		||||
    public interface IQueryableProvider<TSource>
 | 
			
		||||
    {
 | 
			
		||||
        Task<IQueryable<TSource>> GetQueryableAsync(object query, CancellationToken cancellationToken = default);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,13 +0,0 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFramework>netstandard2.1</TargetFramework>
 | 
			
		||||
    <Copyright>Powered Softwares Inc.</Copyright>
 | 
			
		||||
    <PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro</PackageIconUrl>
 | 
			
		||||
    <Company>PoweredSoft</Company>
 | 
			
		||||
    <Authors>PoweredSoft Team</Authors>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="PoweredSoft.DynamicQuery.Core" Version="3.0.1" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@ -1,69 +0,0 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
using PoweredSoft.DynamicQuery;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
 | 
			
		||||
{
 | 
			
		||||
    public class DynamicQuery<TSource, TDestination> : DynamicQuery, IDynamicQuery<TSource, TDestination>
 | 
			
		||||
        where TSource : class
 | 
			
		||||
        where TDestination : class
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class DynamicQuery<TSource, TDestination, TParams> : DynamicQuery, IDynamicQuery<TSource, TDestination, TParams>
 | 
			
		||||
        where TSource : class
 | 
			
		||||
        where TDestination : class
 | 
			
		||||
        where TParams : class
 | 
			
		||||
    {
 | 
			
		||||
        public TParams Params { get; set; }
 | 
			
		||||
 | 
			
		||||
        public TParams GetParams()
 | 
			
		||||
        {
 | 
			
		||||
            return Params;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class DynamicQuery : IDynamicQuery
 | 
			
		||||
    {
 | 
			
		||||
        public int? Page { get; set; }
 | 
			
		||||
        public int? PageSize { get; set; }
 | 
			
		||||
        public List<Sort> Sorts { get; set; }
 | 
			
		||||
        public List<DynamicQueryAggregate> Aggregates { get; set; }
 | 
			
		||||
        public List<Group> Groups { get; set; }
 | 
			
		||||
        public List<DynamicQueryFilter> Filters { get; set; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public List<IAggregate> GetAggregates()
 | 
			
		||||
        {
 | 
			
		||||
            return Aggregates?.Select(t => t.ToAggregate())?.ToList();//.AsEnumerable<IAggregate>()?.ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<IFilter> GetFilters()
 | 
			
		||||
        {
 | 
			
		||||
            return Filters?.Select(t => t.ToFilter())?.ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<IGroup> GetGroups()
 | 
			
		||||
        {
 | 
			
		||||
            return this.Groups?.AsEnumerable<IGroup>()?.ToList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int? GetPage()
 | 
			
		||||
        {
 | 
			
		||||
            return this.Page;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int? GetPageSize()
 | 
			
		||||
        {
 | 
			
		||||
            return this.PageSize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<ISort> GetSorts()
 | 
			
		||||
        {
 | 
			
		||||
            return this.Sorts?.AsEnumerable<ISort>()?.ToList();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,22 +0,0 @@
 | 
			
		||||
using PoweredSoft.DynamicQuery;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
 | 
			
		||||
{
 | 
			
		||||
    public class DynamicQueryAggregate
 | 
			
		||||
    {
 | 
			
		||||
        public string Path { get; set; }
 | 
			
		||||
        public string Type { get; set; }
 | 
			
		||||
 | 
			
		||||
        public IAggregate ToAggregate()
 | 
			
		||||
        {
 | 
			
		||||
            return new Aggregate
 | 
			
		||||
            {
 | 
			
		||||
                Type = Enum.Parse<AggregateType>(Type),
 | 
			
		||||
                Path = Path
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,89 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using PoweredSoft.DynamicQuery;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
 | 
			
		||||
{
 | 
			
		||||
    public class DynamicQueryFilter
 | 
			
		||||
    {
 | 
			
		||||
        public List<DynamicQueryFilter> Filters { get; set; }
 | 
			
		||||
        public bool? And { get; set; }
 | 
			
		||||
        public string Type { get; set; }
 | 
			
		||||
        public bool? Not { get; set; }
 | 
			
		||||
        public string Path { get; set; }
 | 
			
		||||
        public object Value { get; set; }
 | 
			
		||||
 | 
			
		||||
        [FromQuery(Name ="value")]
 | 
			
		||||
        public string QueryValue
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
            set
 | 
			
		||||
            {
 | 
			
		||||
                Value = value;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool? CaseInsensitive { get; set; }
 | 
			
		||||
 | 
			
		||||
        public IFilter ToFilter()
 | 
			
		||||
        {
 | 
			
		||||
            var type = Enum.Parse<FilterType>(Type);
 | 
			
		||||
            if (type == FilterType.Composite)
 | 
			
		||||
            {
 | 
			
		||||
                var compositeFilter = new CompositeFilter
 | 
			
		||||
                {
 | 
			
		||||
                    And = And,
 | 
			
		||||
                    Type = FilterType.Composite,
 | 
			
		||||
                    Filters = Filters?.Select(t => t.ToFilter())?.ToList() ?? new List<IFilter>()
 | 
			
		||||
                };
 | 
			
		||||
                return compositeFilter;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            object value = Value;
 | 
			
		||||
            if (Value is JsonElement jsonElement)
 | 
			
		||||
            {
 | 
			
		||||
                switch (jsonElement.ValueKind)
 | 
			
		||||
                {
 | 
			
		||||
                    case JsonValueKind.String:
 | 
			
		||||
                        value = jsonElement.ToString();
 | 
			
		||||
                        break;
 | 
			
		||||
                    case JsonValueKind.Number:
 | 
			
		||||
                        if (jsonElement.ToString().Contains('.'))
 | 
			
		||||
                            value = jsonElement.GetDecimal();
 | 
			
		||||
                        else if (jsonElement.TryGetInt64(out var convertedValue))
 | 
			
		||||
                            value = convertedValue;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case JsonValueKind.True:
 | 
			
		||||
                        value = true;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case JsonValueKind.False:
 | 
			
		||||
                        value = false;
 | 
			
		||||
                        break;
 | 
			
		||||
                    // TODO: Array support
 | 
			
		||||
                    default:
 | 
			
		||||
                        value = null;
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var simpleFilter = new SimpleFilter
 | 
			
		||||
            {
 | 
			
		||||
                And = And,
 | 
			
		||||
                Type = type,
 | 
			
		||||
                Not = Not,
 | 
			
		||||
                Path = Path,
 | 
			
		||||
                Value = value,
 | 
			
		||||
                CaseInsensitive = CaseInsensitive,
 | 
			
		||||
            };
 | 
			
		||||
            return simpleFilter;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,62 +0,0 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using PoweredSoft.CQRS.Abstractions;
 | 
			
		||||
using PoweredSoft.CQRS.AspNetCore.Mvc;
 | 
			
		||||
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
 | 
			
		||||
using PoweredSoft.DynamicQuery.Core;
 | 
			
		||||
 | 
			
		||||
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
 | 
			
		||||
{
 | 
			
		||||
    [ApiController, Route("api/query/[controller]")]
 | 
			
		||||
    public class DynamicQueryController<TSource, TDestination> : Controller
 | 
			
		||||
        where TSource : class
 | 
			
		||||
        where TDestination : class
 | 
			
		||||
    {
 | 
			
		||||
        [HttpPost, QueryControllerAuthorization]
 | 
			
		||||
        public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
 | 
			
		||||
                [FromBody] DynamicQuery<TSource, TDestination> query, 
 | 
			
		||||
                [FromServices]IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
 | 
			
		||||
            )
 | 
			
		||||
        {
 | 
			
		||||
            var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [HttpGet, QueryControllerAuthorization]
 | 
			
		||||
        public async Task<IQueryExecutionResult<TDestination>> HandleGetAsync(
 | 
			
		||||
                [FromQuery] DynamicQuery<TSource, TDestination> query,
 | 
			
		||||
                [FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
 | 
			
		||||
            )
 | 
			
		||||
        {
 | 
			
		||||
            var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [ApiController, Route("api/query/[controller]")]
 | 
			
		||||
    public class DynamicQueryController<TSource, TDestination, TParams> : Controller
 | 
			
		||||
        where TSource : class
 | 
			
		||||
        where TDestination : class
 | 
			
		||||
        where TParams : class
 | 
			
		||||
    {
 | 
			
		||||
        [HttpPost, QueryControllerAuthorization]
 | 
			
		||||
        public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
 | 
			
		||||
                [FromBody] DynamicQuery<TSource, TDestination, TParams> query,
 | 
			
		||||
                [FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
 | 
			
		||||
            )
 | 
			
		||||
        {
 | 
			
		||||
            var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [HttpGet, QueryControllerAuthorization]
 | 
			
		||||
        public async Task<IQueryExecutionResult<TDestination>> HandleGetAsync(
 | 
			
		||||
                [FromQuery] DynamicQuery<TSource, TDestination, TParams> query,
 | 
			
		||||
                [FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
 | 
			
		||||
            )
 | 
			
		||||
        {
 | 
			
		||||
            var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user