diff --git a/OpenHarbor.CQRS.Abstractions/Attributes/CommandNameAttribute.cs b/OpenHarbor.CQRS.Abstractions/Attributes/CommandNameAttribute.cs new file mode 100644 index 0000000..0b855a8 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Attributes/CommandNameAttribute.cs @@ -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; } +} diff --git a/OpenHarbor.CQRS.Abstractions/Attributes/QueryNameAttribute.cs b/OpenHarbor.CQRS.Abstractions/Attributes/QueryNameAttribute.cs new file mode 100644 index 0000000..831d9c9 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Attributes/QueryNameAttribute.cs @@ -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; } +} + diff --git a/OpenHarbor.CQRS.Abstractions/Discovery/CommandMeta.cs b/OpenHarbor.CQRS.Abstractions/Discovery/CommandMeta.cs new file mode 100644 index 0000000..dcc01d2 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Discovery/CommandMeta.cs @@ -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(); + + 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; + } + } +} + diff --git a/OpenHarbor.CQRS.Abstractions/Discovery/ICommandMeta.cs b/OpenHarbor.CQRS.Abstractions/Discovery/ICommandMeta.cs new file mode 100644 index 0000000..0f2fc31 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Discovery/ICommandMeta.cs @@ -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; } +} + diff --git a/OpenHarbor.CQRS.Abstractions/Discovery/IQueryDiscovery.cs b/OpenHarbor.CQRS.Abstractions/Discovery/IQueryDiscovery.cs new file mode 100644 index 0000000..ecd2cae --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Discovery/IQueryDiscovery.cs @@ -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 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 GetCommands(); +} + diff --git a/OpenHarbor.CQRS.Abstractions/Discovery/IQueryMeta.cs b/OpenHarbor.CQRS.Abstractions/Discovery/IQueryMeta.cs new file mode 100644 index 0000000..0d2d8e3 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Discovery/IQueryMeta.cs @@ -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; } +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.Abstractions/Discovery/QueryMeta.cs b/OpenHarbor.CQRS.Abstractions/Discovery/QueryMeta.cs new file mode 100644 index 0000000..ebde1e2 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Discovery/QueryMeta.cs @@ -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(); + + 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; + } + } +} + diff --git a/OpenHarbor.CQRS.Abstractions/ICommandHandler.cs b/OpenHarbor.CQRS.Abstractions/ICommandHandler.cs new file mode 100644 index 0000000..b928ca0 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/ICommandHandler.cs @@ -0,0 +1,16 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace OpenHarbor.CQRS.Abstractions; + +public interface ICommandHandler + where TCommand : class +{ + Task HandleAsync(TCommand command, CancellationToken cancellationToken = default); +} + +public interface ICommandHandler + where TCommand : class +{ + Task HandleAsync(TCommand command, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.Abstractions/IQueryHandler.cs b/OpenHarbor.CQRS.Abstractions/IQueryHandler.cs new file mode 100644 index 0000000..653b7c3 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/IQueryHandler.cs @@ -0,0 +1,10 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace OpenHarbor.CQRS.Abstractions; + +public interface IQueryHandler + where TQuery : class +{ + Task HandleAsync(TQuery query, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/PoweredSoft.CQRS.Abstractions/PoweredSoft.CQRS.Abstractions.csproj b/OpenHarbor.CQRS.Abstractions/OpenHarbor.CQRS.Abstractions.csproj similarity index 52% rename from PoweredSoft.CQRS.Abstractions/PoweredSoft.CQRS.Abstractions.csproj rename to OpenHarbor.CQRS.Abstractions/OpenHarbor.CQRS.Abstractions.csproj index 63c96a1..1eb00b8 100644 --- a/PoweredSoft.CQRS.Abstractions/PoweredSoft.CQRS.Abstractions.csproj +++ b/OpenHarbor.CQRS.Abstractions/OpenHarbor.CQRS.Abstractions.csproj @@ -1,10 +1,9 @@  netstandard2.1 - Powered Softwares Inc. - https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro - PoweredSoft - PoweredSoft Team + https://avatars.githubusercontent.com/u/52874619?v=4 + David Lebee, Mathias Beaulieu-Duncan + default diff --git a/OpenHarbor.CQRS.Abstractions/Security/AuthorizationResult.cs b/OpenHarbor.CQRS.Abstractions/Security/AuthorizationResult.cs new file mode 100644 index 0000000..a5f0ac4 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Security/AuthorizationResult.cs @@ -0,0 +1,8 @@ +namespace OpenHarbor.CQRS.Abstractions.Security; + +public enum AuthorizationResult +{ + Unauthorized, + Forbidden, + Allowed +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.Abstractions/Security/ICommandAuthorizationService.cs b/OpenHarbor.CQRS.Abstractions/Security/ICommandAuthorizationService.cs new file mode 100644 index 0000000..46d2cb9 --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Security/ICommandAuthorizationService.cs @@ -0,0 +1,10 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace OpenHarbor.CQRS.Abstractions.Security; + +public interface ICommandAuthorizationService +{ + Task IsAllowedAsync(Type commandType, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.Abstractions/Security/IQueryAuthorizationService.cs b/OpenHarbor.CQRS.Abstractions/Security/IQueryAuthorizationService.cs new file mode 100644 index 0000000..32e283c --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/Security/IQueryAuthorizationService.cs @@ -0,0 +1,10 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace OpenHarbor.CQRS.Abstractions.Security; + +public interface IQueryAuthorizationService +{ + Task IsAllowedAsync(Type queryType, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.Abstractions/ServiceCollectionExtensions.cs b/OpenHarbor.CQRS.Abstractions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..df2bd5f --- /dev/null +++ b/OpenHarbor.CQRS.Abstractions/ServiceCollectionExtensions.cs @@ -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(this IServiceCollection services) + where TQuery : class + where TQueryHandler : class, IQueryHandler + { + // add handler to DI. + services.AddTransient, TQueryHandler>(); + + // add for discovery purposes. + var queryMeta = new QueryMeta(typeof(TQuery), typeof(IQueryHandler), typeof(TQueryResult)); + services.AddSingleton(queryMeta); + + return services; + } + + public static IServiceCollection AddCommand(this IServiceCollection services) + where TCommand : class + where TCommandHandler : class, ICommandHandler + { + // add handler to DI. + services.AddTransient, TCommandHandler>(); + + // add for discovery purposes. + var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler), typeof(TCommandResult)); + services.AddSingleton(commandMeta); + + return services; + } + + public static IServiceCollection AddCommand(this IServiceCollection services) + where TCommand : class + where TCommandHandler : class, ICommandHandler + { + // add handler to DI. + services.AddTransient, TCommandHandler>(); + + // add for discovery purposes. + var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler)); + services.AddSingleton(commandMeta); + + return services; + } +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.AspNetCore.Abstractions/Attributes/CommandControllerIgnoreAttribute.cs b/OpenHarbor.CQRS.AspNetCore.Abstractions/Attributes/CommandControllerIgnoreAttribute.cs new file mode 100644 index 0000000..2637a07 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore.Abstractions/Attributes/CommandControllerIgnoreAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace OpenHarbor.CQRS.AspNetCore.Abstractions.Attributes; + +[AttributeUsage(AttributeTargets.Class, Inherited = false)] +public class CommandControllerIgnoreAttribute : Attribute +{ +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.AspNetCore.Abstractions/Attributes/QueryControllerIgnoreAttribute.cs b/OpenHarbor.CQRS.AspNetCore.Abstractions/Attributes/QueryControllerIgnoreAttribute.cs new file mode 100644 index 0000000..5e5d3fa --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore.Abstractions/Attributes/QueryControllerIgnoreAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace OpenHarbor.CQRS.AspNetCore.Abstractions.Attributes; + +[AttributeUsage(AttributeTargets.Class, Inherited = false)] +public class QueryControllerIgnoreAttribute : Attribute +{ +} diff --git a/OpenHarbor.CQRS.AspNetCore.Abstractions/OpenHarbor.CQRS.AspNetCore.Abstractions.csproj b/OpenHarbor.CQRS.AspNetCore.Abstractions/OpenHarbor.CQRS.AspNetCore.Abstractions.csproj new file mode 100644 index 0000000..dabc93e --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore.Abstractions/OpenHarbor.CQRS.AspNetCore.Abstractions.csproj @@ -0,0 +1,8 @@ + + + netstandard2.1 + https://avatars.githubusercontent.com/u/52874619?v=4 + David Lebee, Mathias Beaulieu-Duncan + default + + diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/CommandController.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandController.cs new file mode 100644 index 0000000..fc642eb --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandController.cs @@ -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 : Controller + where TCommand : class +{ + [HttpPost, CommandControllerAuthorization] + public async Task Handle([FromServices] ICommandHandler 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 : Controller + where TCommand : class +{ + [HttpPost, CommandControllerAuthorization] + public async Task> Handle([FromServices] ICommandHandler handler, + [FromBody] TCommand command) + { + if (!ModelState.IsValid) + return BadRequest(ModelState); + + return Ok(await handler.HandleAsync(command, this.Request.HttpContext.RequestAborted)); + } +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerAsyncAuthorizationFilter.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerAsyncAuthorizationFilter.cs new file mode 100644 index 0000000..ff83008 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerAsyncAuthorizationFilter.cs @@ -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(); + } + + 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(); + 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); + } +} diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerAuthorizationAttribute.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerAuthorizationAttribute.cs new file mode 100644 index 0000000..d4ee0fe --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerAuthorizationAttribute.cs @@ -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; +} diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerConvention.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerConvention.cs new file mode 100644 index 0000000..f9cad36 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerConvention.cs @@ -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(); + var command = commandDiscovery.FindCommand(genericType); + controller.ControllerName = command.LowerCamelCaseName; + } +} diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerFeatureProvider.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerFeatureProvider.cs new file mode 100644 index 0000000..1d4ddf1 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerFeatureProvider.cs @@ -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 +{ + private readonly ServiceProvider _serviceProvider; + + public CommandControllerFeatureProvider(ServiceProvider serviceProvider) + { + this._serviceProvider = serviceProvider; + } + + public void PopulateFeature(IEnumerable parts, ControllerFeature feature) + { + var commandDiscovery = this._serviceProvider.GetRequiredService(); + foreach (var f in commandDiscovery.GetCommands()) + { + var ignoreAttribute = f.CommandType.GetCustomAttribute(); + 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); + } + } + } +} diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerOptions.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerOptions.cs new file mode 100644 index 0000000..4ac6614 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/CommandControllerOptions.cs @@ -0,0 +1,6 @@ +namespace OpenHarbor.CQRS.AspNetCore.Mvc; + +public class CommandControllerOptions +{ + +} diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/MvcBuilderExensions.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/MvcBuilderExensions.cs new file mode 100644 index 0000000..dcde62c --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/MvcBuilderExensions.cs @@ -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 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; + } +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/QueryController.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryController.cs new file mode 100644 index 0000000..f96c0e2 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryController.cs @@ -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 : Controller + where TQuery : class +{ + [HttpPost, QueryControllerAuthorization] + public async Task> Handle([FromServices] IQueryHandler 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> HandleGet([FromServices] IQueryHandler handler, + [FromQuery] TQuery query) + { + if (!ModelState.IsValid) + return BadRequest(ModelState); + + + return Ok(await handler.HandleAsync(query, this.Request.HttpContext.RequestAborted)); + } +} diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerAsyncAuthorizationFilter.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerAsyncAuthorizationFilter.cs new file mode 100644 index 0000000..87661a3 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerAsyncAuthorizationFilter.cs @@ -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(); + } + + 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(); + 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); + } +} diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerAuthorizationAttribute.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerAuthorizationAttribute.cs new file mode 100644 index 0000000..6e32c11 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerAuthorizationAttribute.cs @@ -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; } +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerConvention.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerConvention.cs new file mode 100644 index 0000000..ff13bf6 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerConvention.cs @@ -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(); + var query = queryDiscovery.FindQuery(genericType); + controller.ControllerName = query.LowerCamelCaseName; + } + } +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerFeatureProvider.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerFeatureProvider.cs new file mode 100644 index 0000000..de73095 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerFeatureProvider.cs @@ -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 +{ + private readonly ServiceProvider _serviceProvider; + + public QueryControllerFeatureProvider(ServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public void PopulateFeature(IEnumerable parts, ControllerFeature feature) + { + var queryDiscovery = this._serviceProvider.GetRequiredService(); + foreach (var f in queryDiscovery.GetQueries()) + { + var ignoreAttribute = f.QueryType.GetCustomAttribute(); + 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); + } + } +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerOptions.cs b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerOptions.cs new file mode 100644 index 0000000..e2638fa --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/Mvc/QueryControllerOptions.cs @@ -0,0 +1,6 @@ +namespace OpenHarbor.CQRS.AspNetCore.Mvc; + +public class QueryControllerOptions +{ + +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.AspNetCore/OpenHarbor.CQRS.AspNetCore.csproj b/OpenHarbor.CQRS.AspNetCore/OpenHarbor.CQRS.AspNetCore.csproj new file mode 100644 index 0000000..07fd196 --- /dev/null +++ b/OpenHarbor.CQRS.AspNetCore/OpenHarbor.CQRS.AspNetCore.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + https://avatars.githubusercontent.com/u/52874619?v=4 + David Lebee, Mathias Beaulieu-Duncan + true + + + + + + + + + + + + diff --git a/OpenHarbor.CQRS.DynamicQuery.Abstractions/DynamicQueryInterceptorProvider.cs b/OpenHarbor.CQRS.DynamicQuery.Abstractions/DynamicQueryInterceptorProvider.cs new file mode 100644 index 0000000..b5eb6b7 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.Abstractions/DynamicQueryInterceptorProvider.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; + +namespace OpenHarbor.CQRS.DynamicQuery.Abstractions; + +public class DynamicQueryInterceptorProvider : IDynamicQueryInterceptorProvider +{ + private readonly Type[] _types; + + public DynamicQueryInterceptorProvider(params Type[] types) + { + _types = types; + } + + public IEnumerable GetInterceptorsTypes() + { + return _types; + } +} diff --git a/OpenHarbor.CQRS.DynamicQuery.Abstractions/IAlterQueryableService.cs b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IAlterQueryableService.cs new file mode 100644 index 0000000..1c6b0e6 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IAlterQueryableService.cs @@ -0,0 +1,16 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace OpenHarbor.CQRS.DynamicQuery.Abstractions; + +public interface IAlterQueryableService +{ + Task> AlterQueryableAsync(IQueryable query, IDynamicQuery dynamicQuery, CancellationToken cancellationToken = default); +} + +public interface IAlterQueryableService + where TParams : class +{ + Task> AlterQueryableAsync(IQueryable query, IDynamicQueryParams dynamicQuery, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQuery.cs b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQuery.cs new file mode 100644 index 0000000..a5a306f --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQuery.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using PoweredSoft.DynamicQuery.Core; + +namespace OpenHarbor.CQRS.DynamicQuery.Abstractions; + +public interface IDynamicQuery : IDynamicQuery + where TSource : class + where TDestination : class +{ + +} + +public interface IDynamicQuery : IDynamicQuery, IDynamicQueryParams + where TSource : class + where TDestination : class + where TParams : class +{ + +} + +public interface IDynamicQuery +{ + List GetFilters(); + List GetGroups(); + List GetSorts(); + List GetAggregates(); + int? GetPage(); + int? GetPageSize(); +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQueryInterceptorProvider.cs b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQueryInterceptorProvider.cs new file mode 100644 index 0000000..2e7fd48 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQueryInterceptorProvider.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; + +namespace OpenHarbor.CQRS.DynamicQuery.Abstractions; + +public interface IDynamicQueryInterceptorProvider +{ + IEnumerable GetInterceptorsTypes(); +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQueryParams.cs b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQueryParams.cs new file mode 100644 index 0000000..da06839 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IDynamicQueryParams.cs @@ -0,0 +1,7 @@ +namespace OpenHarbor.CQRS.DynamicQuery.Abstractions; + +public interface IDynamicQueryParams + where TParams : class +{ + TParams GetParams(); +} diff --git a/OpenHarbor.CQRS.DynamicQuery.Abstractions/IQueryableProvider.cs b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IQueryableProvider.cs new file mode 100644 index 0000000..6349d1a --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.Abstractions/IQueryableProvider.cs @@ -0,0 +1,10 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace OpenHarbor.CQRS.DynamicQuery.Abstractions; + +public interface IQueryableProvider +{ + Task> GetQueryableAsync(object query, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.DynamicQuery.Abstractions/OpenHarbor.CQRS.DynamicQuery.Abstractions.csproj b/OpenHarbor.CQRS.DynamicQuery.Abstractions/OpenHarbor.CQRS.DynamicQuery.Abstractions.csproj new file mode 100644 index 0000000..bf65d87 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.Abstractions/OpenHarbor.CQRS.DynamicQuery.Abstractions.csproj @@ -0,0 +1,13 @@ + + + netstandard2.1 + enable + https://avatars.githubusercontent.com/u/52874619?v=4 + David Lebee, Mathias Beaulieu-Duncan + default + + + + + + diff --git a/OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQuery.cs b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQuery.cs new file mode 100644 index 0000000..2cad0c7 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQuery.cs @@ -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 : DynamicQuery, IDynamicQuery + where TSource : class + where TDestination : class +{ + +} + +public class DynamicQuery : DynamicQuery, IDynamicQuery + 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 Sorts { get; set; } + public List Aggregates { get; set; } + public List Groups { get; set; } + public List Filters { get; set; } + + + public List GetAggregates() + { + return Aggregates?.Select(t => t.ToAggregate())?.ToList();//.AsEnumerable()?.ToList(); + } + + public List GetFilters() + { + return Filters?.Select(t => t.ToFilter())?.ToList(); + } + + public List GetGroups() + { + return this.Groups?.AsEnumerable()?.ToList(); + } + + public int? GetPage() + { + return this.Page; + } + + public int? GetPageSize() + { + return this.PageSize; + } + + public List GetSorts() + { + return this.Sorts?.AsEnumerable()?.ToList(); + } +} diff --git a/OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQueryAggregate.cs b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQueryAggregate.cs new file mode 100644 index 0000000..234bbdd --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQueryAggregate.cs @@ -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(Type), + Path = Path + }; + } + +} diff --git a/OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQueryFilter.cs b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQueryFilter.cs new file mode 100644 index 0000000..388b06f --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/DynamicQueryFilter.cs @@ -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 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(Type); + if (type == FilterType.Composite) + { + var compositeFilter = new CompositeFilter + { + And = And, + Type = FilterType.Composite, + Filters = Filters?.Select(t => t.ToFilter())?.ToList() ?? new List() + }; + 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; + } +} diff --git a/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryController.cs b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryController.cs new file mode 100644 index 0000000..9d04fb9 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryController.cs @@ -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 : Controller + where TSource : class + where TDestination : class +{ + [HttpPost, QueryControllerAuthorization] + public async Task> HandleAsync( + [FromBody] DynamicQuery query, + [FromServices]IQueryHandler, IQueryExecutionResult> queryHandler + ) + { + var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted); + return result; + } + + [HttpGet, QueryControllerAuthorization] + public async Task> HandleGetAsync( + [FromQuery] DynamicQuery query, + [FromServices] IQueryHandler, IQueryExecutionResult> queryHandler + ) + { + var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted); + return result; + } +} + +[ApiController, Route("api/query/[controller]")] +public class DynamicQueryController : Controller + where TSource : class + where TDestination : class + where TParams : class +{ + [HttpPost, QueryControllerAuthorization] + public async Task> HandleAsync( + [FromBody] DynamicQuery query, + [FromServices] IQueryHandler, IQueryExecutionResult> queryHandler + ) + { + var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted); + return result; + } + + [HttpGet, QueryControllerAuthorization] + public async Task> HandleGetAsync( + [FromQuery] DynamicQuery query, + [FromServices] IQueryHandler, IQueryExecutionResult> queryHandler + ) + { + var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted); + return result; + } +} diff --git a/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerConvention.cs b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerConvention.cs new file mode 100644 index 0000000..70abac4 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerConvention.cs @@ -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(); + var query = queryDiscovery.FindQuery(genericType); + controller.ControllerName = query.LowerCamelCaseName; + } + } +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerFeatureProvider.cs b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerFeatureProvider.cs new file mode 100644 index 0000000..7bb7a01 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerFeatureProvider.cs @@ -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 +{ + private readonly ServiceProvider _serviceProvider; + + public DynamicQueryControllerFeatureProvider(ServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public void PopulateFeature(IEnumerable parts, ControllerFeature feature) + { + var queryDiscovery = _serviceProvider.GetRequiredService(); + foreach (var queryMeta in queryDiscovery.GetQueries()) + { + var ignoreAttribute = queryMeta.QueryType.GetCustomAttribute(); + 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); + } + } + } + } +} diff --git a/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerOptions.cs b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerOptions.cs new file mode 100644 index 0000000..1285b47 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerOptions.cs @@ -0,0 +1,5 @@ +namespace OpenHarbor.CQRS.DynamicQuery.AspNetCore.Mvc; + +public class DynamicQueryControllerOptions +{ +} \ No newline at end of file diff --git a/OpenHarbor.CQRS.DynamicQuery.AspNetCore/MvcBuilderExtensions.cs b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/MvcBuilderExtensions.cs new file mode 100644 index 0000000..843d1e5 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/MvcBuilderExtensions.cs @@ -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 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; + } +} diff --git a/OpenHarbor.CQRS.DynamicQuery.AspNetCore/OpenHarbor.CQRS.DynamicQuery.AspNetCore.csproj b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/OpenHarbor.CQRS.DynamicQuery.AspNetCore.csproj new file mode 100644 index 0000000..409f6d3 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery.AspNetCore/OpenHarbor.CQRS.DynamicQuery.AspNetCore.csproj @@ -0,0 +1,20 @@ + + + net8.0 + https://avatars.githubusercontent.com/u/52874619?v=4 + David Lebee, Mathias Beaulieu-Duncan + true + + + + + + + + + + + + + + diff --git a/OpenHarbor.CQRS.DynamicQuery/Discover/DynamicQueryMeta.cs b/OpenHarbor.CQRS.DynamicQuery/Discover/DynamicQueryMeta.cs new file mode 100644 index 0000000..6d4e500 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery/Discover/DynamicQueryMeta.cs @@ -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; } +} + diff --git a/OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandler.cs b/OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandler.cs new file mode 100644 index 0000000..1446b1a --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandler.cs @@ -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 + : DynamicQueryHandlerBase, + OpenHarbor.CQRS.Abstractions.IQueryHandler, IQueryExecutionResult> + where TSource : class + where TDestination : class +{ + public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync, + IEnumerable> queryableProviders, + IEnumerable> alterQueryableServices, + IEnumerable> dynamicQueryInterceptorProviders, + IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, dynamicQueryInterceptorProviders, serviceProvider) + { + } + + public Task> HandleAsync(IDynamicQuery query, CancellationToken cancellationToken = default) + { + return ProcessQueryAsync(query, cancellationToken); + } +} + +public class DynamicQueryHandler + : DynamicQueryHandlerBase, + OpenHarbor.CQRS.Abstractions.IQueryHandler, IQueryExecutionResult> + where TSource : class + where TDestination : class + where TParams : class +{ + private readonly IEnumerable> alterQueryableServicesWithParams; + + public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync, + IEnumerable> queryableProviders, + IEnumerable> alterQueryableServices, + IEnumerable> alterQueryableServicesWithParams, + IEnumerable> dynamicQueryInterceptorProviders, + IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, dynamicQueryInterceptorProviders, serviceProvider) + { + this.alterQueryableServicesWithParams = alterQueryableServicesWithParams; + } + + protected override async Task> AlterSourceAsync(IQueryable source, IDynamicQuery query, CancellationToken cancellationToken) + { + source = await base.AlterSourceAsync(source, query, cancellationToken); + + if (query is IDynamicQueryParams withParams) + { + foreach (var it in alterQueryableServicesWithParams) + source = await it.AlterQueryableAsync(source, withParams, cancellationToken); + } + + return source; + } + + public Task> HandleAsync(IDynamicQuery query, CancellationToken cancellationToken = default) + { + return this.ProcessQueryAsync(query, cancellationToken); + } +} diff --git a/OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandlerBase.cs b/OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandlerBase.cs new file mode 100644 index 0000000..3188f7c --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery/DynamicQueryHandlerBase.cs @@ -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 + where TSource : class + where TDestination : class +{ + private readonly IQueryHandlerAsync _queryHandlerAsync; + private readonly IEnumerable> _queryableProviders; + private readonly IEnumerable> _alterQueryableServices; + private readonly IEnumerable> _dynamicQueryInterceptorProviders; + private readonly IServiceProvider _serviceProvider; + + public DynamicQueryHandlerBase(IQueryHandlerAsync queryHandlerAsync, + IEnumerable> queryableProviders, + IEnumerable> alterQueryableServices, + IEnumerable> dynamicQueryInterceptorProviders, + IServiceProvider serviceProvider) + { + _queryHandlerAsync = queryHandlerAsync; + _queryableProviders = queryableProviders; + _alterQueryableServices = alterQueryableServices; + _dynamicQueryInterceptorProviders = dynamicQueryInterceptorProviders; + _serviceProvider = serviceProvider; + } + + protected virtual Task> GetQueryableAsync(IDynamicQuery query, CancellationToken cancellationToken = default) + { + if (_queryableProviders.Any()) + return _queryableProviders.ElementAt(0).GetQueryableAsync(query, cancellationToken); + + throw new Exception($"You must provide a QueryableProvider for {typeof(TSource).Name}"); + } + + public virtual IQueryExecutionOptions GetQueryExecutionOptions(IQueryable source, IDynamicQuery query) + { + return new QueryExecutionOptions(); + } + + public virtual IEnumerable GetInterceptors() + { + var types = _dynamicQueryInterceptorProviders.SelectMany(t => t.GetInterceptorsTypes()).Distinct(); + foreach (var type in types) + yield return _serviceProvider.GetService(type) as IQueryInterceptor; + } + + protected async Task> 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(source, criteria, options, cancellationToken); + return result; + } + + protected virtual async Task> AlterSourceAsync(IQueryable 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(), + Sorts = query?.GetSorts() ?? new List(), + Groups = query?.GetGroups() ?? new List(), + Aggregates = query?.GetAggregates() ?? new List() + }; + return criteria; + } +} + diff --git a/OpenHarbor.CQRS.DynamicQuery/OpenHarbor.CQRS.DynamicQuery.csproj b/OpenHarbor.CQRS.DynamicQuery/OpenHarbor.CQRS.DynamicQuery.csproj new file mode 100644 index 0000000..19fe117 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery/OpenHarbor.CQRS.DynamicQuery.csproj @@ -0,0 +1,18 @@ + + + netstandard2.1 + https://avatars.githubusercontent.com/u/52874619?v=4 + David Lebee, Mathias Beaulieu-Duncan + default + + + + + + + + + + + + diff --git a/OpenHarbor.CQRS.DynamicQuery/ServiceCollectionExtensions.cs b/OpenHarbor.CQRS.DynamicQuery/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..f97f2c4 --- /dev/null +++ b/OpenHarbor.CQRS.DynamicQuery/ServiceCollectionExtensions.cs @@ -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(this IServiceCollection services, string name = null) + where TSourceAndDestination : class + => AddDynamicQuery(services, name: name); + + public static IServiceCollection AddDynamicQuery(this IServiceCollection services, string name = null) + where TSource : class + where TDestination : class + { + // add query handler. + services.AddTransient, IQueryExecutionResult>, DynamicQueryHandler>(); + + // add for discovery purposes. + var queryType = typeof(IDynamicQuery); + var resultType = typeof(IQueryExecutionResult); + var serviceType = typeof(DynamicQueryHandler); + var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType) + { + OverridableName = name + }; + + services.AddSingleton(queryMeta); + + return services; + } + + public static IServiceCollection AddDynamicQueryWithProvider(this IServiceCollection services, string name = null) + where TQueryableProvider : class, IQueryableProvider + where TSource : class + { + services.AddTransient, TQueryableProvider>() + .AddDynamicQuery(name: name); + return services; + } + + public static IServiceCollection AddDynamicQueryWithParamsAndProvider(this IServiceCollection services, string name = null) + where TQueryableProvider : class, IQueryableProvider + where TParams : class + where TSource : class + { + services.AddTransient, TQueryableProvider>() + .AddDynamicQueryWithParams(name: name); + return services; + } + + public static IServiceCollection AddDynamicQueryWithParams(this IServiceCollection services, string name = null) + where TSourceAndDestination : class + where TParams : class + => AddDynamicQueryWithParams(services, name: name); + + public static IServiceCollection AddDynamicQueryWithParams(this IServiceCollection services, string name = null) + where TSource : class + where TDestination : class + where TParams : class + { + // add query handler. + services.AddTransient, IQueryExecutionResult>, DynamicQueryHandler>(); + + // add for discovery purposes. + var queryType = typeof(IDynamicQuery); + var resultType = typeof(IQueryExecutionResult); + var serviceType = typeof(DynamicQueryHandler); + var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType) + { + + // params type. + ParamsType = typeof(TParams), + OverridableName = name + }; + + services.AddSingleton(queryMeta); + + return services; + } + + public static IServiceCollection AddAlterQueryable(this IServiceCollection services) + where TService : class, IAlterQueryableService + { + return services.AddTransient, TService>(); + } + + public static IServiceCollection AddAlterQueryable(this IServiceCollection services) + where TService : class, IAlterQueryableService + { + return services.AddTransient, TService>(); + } + + public static IServiceCollection AddAlterQueryableWithParams + (this IServiceCollection services) + where TParams : class + where TService : class, IAlterQueryableService + { + return services.AddTransient, TService>(); + } + + public static IServiceCollection AddAlterQueryableWithParams + (this IServiceCollection services) + where TParams : class + where TService : class, IAlterQueryableService + { + return services.AddTransient, TService>(); + } + + public static IServiceCollection AddDynamicQueryInterceptor(this IServiceCollection services) + where TInterceptor : class, IQueryInterceptor + { + services.TryAddTransient(); + return services.AddSingleton>( + new DynamicQueryInterceptorProvider(typeof(TInterceptor))); + } + + public static IServiceCollection AddDynamicQueryInterceptors(this IServiceCollection services) + where T1 : class, IQueryInterceptor + where T2 : class, IQueryInterceptor + { + services.TryAddTransient(); + services.TryAddTransient(); + return services.AddSingleton>( + new DynamicQueryInterceptorProvider(typeof(T1), typeof(T2))); + } + + public static IServiceCollection AddDynamicQueryInterceptors(this IServiceCollection services) + where T1 : class, IQueryInterceptor + where T2 : class, IQueryInterceptor + where T3 : class, IQueryInterceptor + { + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); + return services.AddSingleton>( + new DynamicQueryInterceptorProvider(typeof(T1), typeof(T2), typeof(T3))); + } + + public static IServiceCollection AddDynamicQueryInterceptors(this IServiceCollection services) + where T1 : class, IQueryInterceptor + where T2 : class, IQueryInterceptor + where T3 : class, IQueryInterceptor + where T4 : class, IQueryInterceptor + { + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); + return services.AddSingleton>( + new DynamicQueryInterceptorProvider(typeof(T1), typeof(T2), typeof(T3), typeof(T4))); + } + + public static IServiceCollection AddDynamicQueryInterceptors(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(); + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); + return services.AddSingleton>( + new DynamicQueryInterceptorProvider(typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5))); + } +} + diff --git a/OpenHarbor.CQRS.FluentValidation/OpenHarbor.CQRS.FluentValidation.csproj b/OpenHarbor.CQRS.FluentValidation/OpenHarbor.CQRS.FluentValidation.csproj new file mode 100644 index 0000000..9109223 --- /dev/null +++ b/OpenHarbor.CQRS.FluentValidation/OpenHarbor.CQRS.FluentValidation.csproj @@ -0,0 +1,16 @@ + + + netstandard2.1 + https://avatars.githubusercontent.com/u/52874619?v=4 + David Lebee, Mathias Beaulieu-Duncan + default + + + + + + + + + + diff --git a/OpenHarbor.CQRS.FluentValidation/ServiceCollectionExtensions.cs b/OpenHarbor.CQRS.FluentValidation/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..2058d59 --- /dev/null +++ b/OpenHarbor.CQRS.FluentValidation/ServiceCollectionExtensions.cs @@ -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(this IServiceCollection services) + where TValidator : class, IValidator + { + services.AddTransient, TValidator>(); + return services; + } + + public static IServiceCollection AddCommand(this IServiceCollection services) + where TCommand : class + where TCommandHandler : class, ICommandHandler + where TValidator : class, IValidator + { + return services.AddCommand() + .AddFluentValidator(); + } + + public static IServiceCollection AddCommand(this IServiceCollection services) + where TCommand : class + where TCommandHandler : class, ICommandHandler + where TValidator : class, IValidator + { + return services.AddCommand() + .AddFluentValidator(); + } + + public static IServiceCollection AddQuery(this IServiceCollection services) + where TQuery : class + where TQueryHandler : class, IQueryHandler + where TValidator : class, IValidator + { + services.AddQuery() + .AddFluentValidator(); + return services; + } +} \ No newline at end of file diff --git a/PoweredSoft.CQRS.sln b/OpenHarbor.CQRS.sln similarity index 63% rename from PoweredSoft.CQRS.sln rename to OpenHarbor.CQRS.sln index 4256da3..43ca665 100644 --- a/PoweredSoft.CQRS.sln +++ b/OpenHarbor.CQRS.sln @@ -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 diff --git a/OpenHarbor.CQRS/Discovery/CommandDiscovery.cs b/OpenHarbor.CQRS/Discovery/CommandDiscovery.cs new file mode 100644 index 0000000..da91c9c --- /dev/null +++ b/OpenHarbor.CQRS/Discovery/CommandDiscovery.cs @@ -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 _commandMetas; + + public CommandDiscovery(IEnumerable commandMetas) + { + _commandMetas = commandMetas; + } + + public IEnumerable 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); +} diff --git a/OpenHarbor.CQRS/Discovery/QueryDiscovery.cs b/OpenHarbor.CQRS/Discovery/QueryDiscovery.cs new file mode 100644 index 0000000..08670fe --- /dev/null +++ b/OpenHarbor.CQRS/Discovery/QueryDiscovery.cs @@ -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 _queryMetas; + + public QueryDiscovery(IEnumerable queryMetas) + { + _queryMetas = queryMetas; + } + + public IEnumerable 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); +} + diff --git a/OpenHarbor.CQRS/OpenHarbor.CQRS.csproj b/OpenHarbor.CQRS/OpenHarbor.CQRS.csproj new file mode 100644 index 0000000..23fafe9 --- /dev/null +++ b/OpenHarbor.CQRS/OpenHarbor.CQRS.csproj @@ -0,0 +1,12 @@ + + + netstandard2.1 + https://avatars.githubusercontent.com/u/52874619?v=4 + David Lebee, Mathias Beaulieu-Duncan + default + + + + + + diff --git a/OpenHarbor.CQRS/ServiceCollectionExtensions.cs b/OpenHarbor.CQRS/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..c335420 --- /dev/null +++ b/OpenHarbor.CQRS/ServiceCollectionExtensions.cs @@ -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(); + return services; + } + + public static IServiceCollection AddDefaultCommandDiscovery(this IServiceCollection services) + { + services.TryAddTransient(); + return services; + } +} diff --git a/PoweredSoft.CQRS.Abstractions/Attributes/CommandNameAttribute.cs b/PoweredSoft.CQRS.Abstractions/Attributes/CommandNameAttribute.cs deleted file mode 100644 index 04880c4..0000000 --- a/PoweredSoft.CQRS.Abstractions/Attributes/CommandNameAttribute.cs +++ /dev/null @@ -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; } - } -} diff --git a/PoweredSoft.CQRS.Abstractions/Attributes/QueryNameAttribute.cs b/PoweredSoft.CQRS.Abstractions/Attributes/QueryNameAttribute.cs deleted file mode 100644 index 329b996..0000000 --- a/PoweredSoft.CQRS.Abstractions/Attributes/QueryNameAttribute.cs +++ /dev/null @@ -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; } - } -} diff --git a/PoweredSoft.CQRS.Abstractions/Discovery/CommandMeta.cs b/PoweredSoft.CQRS.Abstractions/Discovery/CommandMeta.cs deleted file mode 100644 index 1645151..0000000 --- a/PoweredSoft.CQRS.Abstractions/Discovery/CommandMeta.cs +++ /dev/null @@ -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(); - - 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; - } - } - } -} diff --git a/PoweredSoft.CQRS.Abstractions/Discovery/ICommandMeta.cs b/PoweredSoft.CQRS.Abstractions/Discovery/ICommandMeta.cs deleted file mode 100644 index cbfb257..0000000 --- a/PoweredSoft.CQRS.Abstractions/Discovery/ICommandMeta.cs +++ /dev/null @@ -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; } - } -} diff --git a/PoweredSoft.CQRS.Abstractions/Discovery/IQueryDiscovery.cs b/PoweredSoft.CQRS.Abstractions/Discovery/IQueryDiscovery.cs deleted file mode 100644 index 6e335fb..0000000 --- a/PoweredSoft.CQRS.Abstractions/Discovery/IQueryDiscovery.cs +++ /dev/null @@ -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 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 GetCommands(); - } -} diff --git a/PoweredSoft.CQRS.Abstractions/Discovery/IQueryMeta.cs b/PoweredSoft.CQRS.Abstractions/Discovery/IQueryMeta.cs deleted file mode 100644 index e272317..0000000 --- a/PoweredSoft.CQRS.Abstractions/Discovery/IQueryMeta.cs +++ /dev/null @@ -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; } - } -} diff --git a/PoweredSoft.CQRS.Abstractions/Discovery/QueryMeta.cs b/PoweredSoft.CQRS.Abstractions/Discovery/QueryMeta.cs deleted file mode 100644 index d866adc..0000000 --- a/PoweredSoft.CQRS.Abstractions/Discovery/QueryMeta.cs +++ /dev/null @@ -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(); - - 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; - } - } - } -} diff --git a/PoweredSoft.CQRS.Abstractions/ICommandHandler.cs b/PoweredSoft.CQRS.Abstractions/ICommandHandler.cs deleted file mode 100644 index e36dfa1..0000000 --- a/PoweredSoft.CQRS.Abstractions/ICommandHandler.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace PoweredSoft.CQRS.Abstractions -{ - public interface ICommandHandler - where TCommand : class - { - Task HandleAsync(TCommand command, CancellationToken cancellationToken = default); - } - - public interface ICommandHandler - where TCommand : class - { - Task HandleAsync(TCommand command, CancellationToken cancellationToken = default); - } -} diff --git a/PoweredSoft.CQRS.Abstractions/IQueryHandler.cs b/PoweredSoft.CQRS.Abstractions/IQueryHandler.cs deleted file mode 100644 index a3116b3..0000000 --- a/PoweredSoft.CQRS.Abstractions/IQueryHandler.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace PoweredSoft.CQRS.Abstractions -{ - public interface IQueryHandler - where TQuery : class - { - Task HandleAsync(TQuery query, CancellationToken cancellationToken = default); - } -} diff --git a/PoweredSoft.CQRS.Abstractions/Security/AuthorizationResult.cs b/PoweredSoft.CQRS.Abstractions/Security/AuthorizationResult.cs deleted file mode 100644 index 7520d88..0000000 --- a/PoweredSoft.CQRS.Abstractions/Security/AuthorizationResult.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace PoweredSoft.CQRS.Abstractions.Security -{ - public enum AuthorizationResult - { - Unauthorized, - Forbidden, - Allowed - } -} diff --git a/PoweredSoft.CQRS.Abstractions/Security/ICommandAuthorizationService.cs b/PoweredSoft.CQRS.Abstractions/Security/ICommandAuthorizationService.cs deleted file mode 100644 index fea7568..0000000 --- a/PoweredSoft.CQRS.Abstractions/Security/ICommandAuthorizationService.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace PoweredSoft.CQRS.Abstractions.Security -{ - public interface ICommandAuthorizationService - { - Task IsAllowedAsync(Type commandType, CancellationToken cancellationToken = default); - } -} diff --git a/PoweredSoft.CQRS.Abstractions/Security/IQueryAuthorizationService.cs b/PoweredSoft.CQRS.Abstractions/Security/IQueryAuthorizationService.cs deleted file mode 100644 index a4d1d55..0000000 --- a/PoweredSoft.CQRS.Abstractions/Security/IQueryAuthorizationService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace PoweredSoft.CQRS.Abstractions.Security -{ - - public interface IQueryAuthorizationService - { - Task IsAllowedAsync(Type queryType, CancellationToken cancellationToken = default); - } -} diff --git a/PoweredSoft.CQRS.Abstractions/ServiceCollectionExtensions.cs b/PoweredSoft.CQRS.Abstractions/ServiceCollectionExtensions.cs deleted file mode 100644 index ee920d6..0000000 --- a/PoweredSoft.CQRS.Abstractions/ServiceCollectionExtensions.cs +++ /dev/null @@ -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(this IServiceCollection services) - where TQuery : class - where TQueryHandler : class, IQueryHandler - { - // add handler to DI. - services.AddTransient, TQueryHandler>(); - - // add for discovery purposes. - var queryMeta = new QueryMeta(typeof(TQuery), typeof(IQueryHandler), typeof(TQueryResult)); - services.AddSingleton(queryMeta); - - return services; - } - - public static IServiceCollection AddCommand(this IServiceCollection services) - where TCommand : class - where TCommandHandler : class, ICommandHandler - { - // add handler to DI. - services.AddTransient, TCommandHandler>(); - - // add for discovery purposes. - var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler), typeof(TCommandResult)); - services.AddSingleton(commandMeta); - - return services; - } - - public static IServiceCollection AddCommand(this IServiceCollection services) - where TCommand : class - where TCommandHandler : class, ICommandHandler - { - // add handler to DI. - services.AddTransient, TCommandHandler>(); - - // add for discovery purposes. - var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler)); - services.AddSingleton(commandMeta); - - return services; - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore.Abstractions/Attributes/CommandControllerIgnoreAttribute.cs b/PoweredSoft.CQRS.AspNetCore.Abstractions/Attributes/CommandControllerIgnoreAttribute.cs deleted file mode 100644 index 10c1706..0000000 --- a/PoweredSoft.CQRS.AspNetCore.Abstractions/Attributes/CommandControllerIgnoreAttribute.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace PoweredSoft.CQRS.AspNetCore.Abstractions.Attributes -{ - [AttributeUsage(AttributeTargets.Class, Inherited = false)] - public class CommandControllerIgnoreAttribute : Attribute - { - } -} diff --git a/PoweredSoft.CQRS.AspNetCore.Abstractions/Attributes/QueryControllerIgnoreAttribute.cs b/PoweredSoft.CQRS.AspNetCore.Abstractions/Attributes/QueryControllerIgnoreAttribute.cs deleted file mode 100644 index 8cc10ff..0000000 --- a/PoweredSoft.CQRS.AspNetCore.Abstractions/Attributes/QueryControllerIgnoreAttribute.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace PoweredSoft.CQRS.AspNetCore.Abstractions.Attributes -{ - [AttributeUsage(AttributeTargets.Class, Inherited = false)] - public class QueryControllerIgnoreAttribute : Attribute - { - } -} diff --git a/PoweredSoft.CQRS.AspNetCore.Abstractions/PoweredSoft.CQRS.AspNetCore.Abstractions.csproj b/PoweredSoft.CQRS.AspNetCore.Abstractions/PoweredSoft.CQRS.AspNetCore.Abstractions.csproj deleted file mode 100644 index 88e46c2..0000000 --- a/PoweredSoft.CQRS.AspNetCore.Abstractions/PoweredSoft.CQRS.AspNetCore.Abstractions.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - netstandard2.1 - Powered Softwares Inc. - https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro - PoweredSoft - PoweredSoft Team - - diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandController.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/CommandController.cs deleted file mode 100644 index e48bba9..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandController.cs +++ /dev/null @@ -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 : Controller - where TCommand : class - { - [HttpPost, CommandControllerAuthorization] - public async Task Handle([FromServices] ICommandHandler 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 : Controller - where TCommand : class - { - [HttpPost, CommandControllerAuthorization] - public async Task> Handle([FromServices] ICommandHandler handler, - [FromBody] TCommand command) - { - if (!ModelState.IsValid) - return BadRequest(ModelState); - - return Ok(await handler.HandleAsync(command, this.Request.HttpContext.RequestAborted)); - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerAsyncAuthorizationFilter.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerAsyncAuthorizationFilter.cs deleted file mode 100644 index 332c755..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerAsyncAuthorizationFilter.cs +++ /dev/null @@ -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(); - } - - 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(); - 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); - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerAuthorizationAttribute.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerAuthorizationAttribute.cs deleted file mode 100644 index a114640..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerAuthorizationAttribute.cs +++ /dev/null @@ -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; - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerConvention.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerConvention.cs deleted file mode 100644 index deacea3..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerConvention.cs +++ /dev/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(); - var command = commandDiscovery.FindCommand(genericType); - controller.ControllerName = command.LowerCamelCaseName; - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerFeatureProvider.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerFeatureProvider.cs deleted file mode 100644 index 16207fe..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerFeatureProvider.cs +++ /dev/null @@ -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 - { - private readonly ServiceProvider serviceProvider; - - public CommandControllerFeatureProvider(ServiceProvider serviceProvider) - { - this.serviceProvider = serviceProvider; - } - - public void PopulateFeature(IEnumerable parts, ControllerFeature feature) - { - var commandDiscovery = this.serviceProvider.GetRequiredService(); - foreach (var f in commandDiscovery.GetCommands()) - { - var ignoreAttribute = f.CommandType.GetCustomAttribute(); - 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); - } - } - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerOptions.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerOptions.cs deleted file mode 100644 index 9ee49a4..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/CommandControllerOptions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace PoweredSoft.CQRS.AspNetCore.Mvc -{ - public class CommandControllerOptions - { - - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryController.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/QueryController.cs deleted file mode 100644 index 038496d..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryController.cs +++ /dev/null @@ -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 : Controller - where TQuery : class - { - [HttpPost, QueryControllerAuthorization] - public async Task> Handle([FromServices] IQueryHandler 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> HandleGet([FromServices] IQueryHandler handler, - [FromQuery] TQuery query) - { - if (!ModelState.IsValid) - return BadRequest(ModelState); - - - return Ok(await handler.HandleAsync(query, this.Request.HttpContext.RequestAborted)); - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerAsyncAuthorizationFilter.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerAsyncAuthorizationFilter.cs deleted file mode 100644 index c032390..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerAsyncAuthorizationFilter.cs +++ /dev/null @@ -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(); - } - - 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(); - 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); - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerAuthorizationAttribute.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerAuthorizationAttribute.cs deleted file mode 100644 index 3daedbe..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerAuthorizationAttribute.cs +++ /dev/null @@ -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; - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerConvention.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerConvention.cs deleted file mode 100644 index ccbf0a1..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerConvention.cs +++ /dev/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(); - var query = queryDiscovery.FindQuery(genericType); - controller.ControllerName = query.LowerCamelCaseName; - } - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerFeatureProvider.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerFeatureProvider.cs deleted file mode 100644 index e15065b..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerFeatureProvider.cs +++ /dev/null @@ -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 - { - private readonly ServiceProvider serviceProvider; - - public QueryControllerFeatureProvider(ServiceProvider serviceProvider) - { - this.serviceProvider = serviceProvider; - } - - public void PopulateFeature(IEnumerable parts, ControllerFeature feature) - { - var queryDiscovery = this.serviceProvider.GetRequiredService(); - foreach (var f in queryDiscovery.GetQueries()) - { - var ignoreAttribute = f.QueryType.GetCustomAttribute(); - 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); - } - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerOptions.cs b/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerOptions.cs deleted file mode 100644 index 4ed12ea..0000000 --- a/PoweredSoft.CQRS.AspNetCore/Mvc/QueryControllerOptions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace PoweredSoft.CQRS.AspNetCore.Mvc -{ - public class QueryControllerOptions - { - - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/MvcBuilderExensions.cs b/PoweredSoft.CQRS.AspNetCore/MvcBuilderExensions.cs deleted file mode 100644 index 64bb065..0000000 --- a/PoweredSoft.CQRS.AspNetCore/MvcBuilderExensions.cs +++ /dev/null @@ -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 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; - } - } -} diff --git a/PoweredSoft.CQRS.AspNetCore/PoweredSoft.CQRS.AspNetCore.csproj b/PoweredSoft.CQRS.AspNetCore/PoweredSoft.CQRS.AspNetCore.csproj deleted file mode 100644 index 85de34e..0000000 --- a/PoweredSoft.CQRS.AspNetCore/PoweredSoft.CQRS.AspNetCore.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - net8.0 - Powered Softwares Inc. - https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro - PoweredSoft - PoweredSoft Team - true - - - - - - - - - - - - diff --git a/PoweredSoft.CQRS.DynamicQuery.Abstractions/DynamicQueryInterceptorProvider.cs b/PoweredSoft.CQRS.DynamicQuery.Abstractions/DynamicQueryInterceptorProvider.cs deleted file mode 100644 index 94ba9b9..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.Abstractions/DynamicQueryInterceptorProvider.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace PoweredSoft.CQRS.DynamicQuery.Abstractions -{ - public class DynamicQueryInterceptorProvider : IDynamicQueryInterceptorProvider - { - private readonly Type[] types; - - public DynamicQueryInterceptorProvider(params Type[] types) - { - this.types = types; - } - - public IEnumerable GetInterceptorsTypes() - { - return types; - } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IAlterQueryableService.cs b/PoweredSoft.CQRS.DynamicQuery.Abstractions/IAlterQueryableService.cs deleted file mode 100644 index 06279ee..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IAlterQueryableService.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace PoweredSoft.CQRS.DynamicQuery.Abstractions -{ - public interface IAlterQueryableService - { - Task> AlterQueryableAsync(IQueryable query, IDynamicQuery dynamicQuery, CancellationToken cancellationToken = default); - } - public interface IAlterQueryableService - where TParams : class - { - Task> AlterQueryableAsync(IQueryable query, IDynamicQueryParams dynamicQuery, CancellationToken cancellationToken = default); - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IDynamicQuery.cs b/PoweredSoft.CQRS.DynamicQuery.Abstractions/IDynamicQuery.cs deleted file mode 100644 index 923ccdf..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IDynamicQuery.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using PoweredSoft.DynamicQuery.Core; - -namespace PoweredSoft.CQRS.DynamicQuery.Abstractions -{ - public interface IDynamicQuery : IDynamicQuery - where TSource : class - where TDestination : class - { - - } - - public interface IDynamicQuery : IDynamicQuery, IDynamicQueryParams - where TSource : class - where TDestination : class - where TParams : class - { - - } - - public interface IDynamicQuery - { - List GetFilters(); - List GetGroups(); - List GetSorts(); - List GetAggregates(); - int? GetPage(); - int? GetPageSize(); - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IDynamicQueryInterceptorProvider.cs b/PoweredSoft.CQRS.DynamicQuery.Abstractions/IDynamicQueryInterceptorProvider.cs deleted file mode 100644 index ee6e405..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IDynamicQueryInterceptorProvider.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace PoweredSoft.CQRS.DynamicQuery.Abstractions -{ - public interface IDynamicQueryInterceptorProvider - { - IEnumerable GetInterceptorsTypes(); - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IDynamicQueryParams.cs b/PoweredSoft.CQRS.DynamicQuery.Abstractions/IDynamicQueryParams.cs deleted file mode 100644 index 51f877f..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IDynamicQueryParams.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace PoweredSoft.CQRS.DynamicQuery.Abstractions -{ - public interface IDynamicQueryParams - where TParams : class - { - TParams GetParams(); - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IQueryableProvider.cs b/PoweredSoft.CQRS.DynamicQuery.Abstractions/IQueryableProvider.cs deleted file mode 100644 index 6a9f566..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.Abstractions/IQueryableProvider.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace PoweredSoft.CQRS.DynamicQuery.Abstractions -{ - public interface IQueryableProvider - { - Task> GetQueryableAsync(object query, CancellationToken cancellationToken = default); - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.Abstractions/PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj b/PoweredSoft.CQRS.DynamicQuery.Abstractions/PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj deleted file mode 100644 index 3f0fa63..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.Abstractions/PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - netstandard2.1 - Powered Softwares Inc. - https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro - PoweredSoft - PoweredSoft Team - - - - - - diff --git a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/DynamicQuery.cs b/PoweredSoft.CQRS.DynamicQuery.AspNetCore/DynamicQuery.cs deleted file mode 100644 index a9df635..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/DynamicQuery.cs +++ /dev/null @@ -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 : DynamicQuery, IDynamicQuery - where TSource : class - where TDestination : class - { - - } - - public class DynamicQuery : DynamicQuery, IDynamicQuery - 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 Sorts { get; set; } - public List Aggregates { get; set; } - public List Groups { get; set; } - public List Filters { get; set; } - - - public List GetAggregates() - { - return Aggregates?.Select(t => t.ToAggregate())?.ToList();//.AsEnumerable()?.ToList(); - } - - public List GetFilters() - { - return Filters?.Select(t => t.ToFilter())?.ToList(); - } - - public List GetGroups() - { - return this.Groups?.AsEnumerable()?.ToList(); - } - - public int? GetPage() - { - return this.Page; - } - - public int? GetPageSize() - { - return this.PageSize; - } - - public List GetSorts() - { - return this.Sorts?.AsEnumerable()?.ToList(); - } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/DynamicQueryAggregate.cs b/PoweredSoft.CQRS.DynamicQuery.AspNetCore/DynamicQueryAggregate.cs deleted file mode 100644 index f803a14..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/DynamicQueryAggregate.cs +++ /dev/null @@ -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(Type), - Path = Path - }; - } - - } -} \ No newline at end of file diff --git a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/DynamicQueryFilter.cs b/PoweredSoft.CQRS.DynamicQuery.AspNetCore/DynamicQueryFilter.cs deleted file mode 100644 index a48adc0..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/DynamicQueryFilter.cs +++ /dev/null @@ -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 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(Type); - if (type == FilterType.Composite) - { - var compositeFilter = new CompositeFilter - { - And = And, - Type = FilterType.Composite, - Filters = Filters?.Select(t => t.ToFilter())?.ToList() ?? new List() - }; - 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; - } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryController.cs b/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryController.cs deleted file mode 100644 index cf142e3..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryController.cs +++ /dev/null @@ -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 : Controller - where TSource : class - where TDestination : class - { - [HttpPost, QueryControllerAuthorization] - public async Task> HandleAsync( - [FromBody] DynamicQuery query, - [FromServices]IQueryHandler, IQueryExecutionResult> queryHandler - ) - { - var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted); - return result; - } - - [HttpGet, QueryControllerAuthorization] - public async Task> HandleGetAsync( - [FromQuery] DynamicQuery query, - [FromServices] IQueryHandler, IQueryExecutionResult> queryHandler - ) - { - var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted); - return result; - } - } - - [ApiController, Route("api/query/[controller]")] - public class DynamicQueryController : Controller - where TSource : class - where TDestination : class - where TParams : class - { - [HttpPost, QueryControllerAuthorization] - public async Task> HandleAsync( - [FromBody] DynamicQuery query, - [FromServices] IQueryHandler, IQueryExecutionResult> queryHandler - ) - { - var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted); - return result; - } - - [HttpGet, QueryControllerAuthorization] - public async Task> HandleGetAsync( - [FromQuery] DynamicQuery query, - [FromServices] IQueryHandler, IQueryExecutionResult> queryHandler - ) - { - var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted); - return result; - } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerConvention.cs b/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerConvention.cs deleted file mode 100644 index 841a22f..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerConvention.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using Microsoft.AspNetCore.Mvc.ApplicationModels; -using Microsoft.Extensions.DependencyInjection; -using PoweredSoft.CQRS.Abstractions.Discovery; - -namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc -{ - public class DynamicQueryControllerConvention : IControllerModelConvention - { - private readonly IServiceProvider serviceProvider; - - public DynamicQueryControllerConvention(IServiceProvider serviceProvider) - { - this.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 = this.serviceProvider.GetRequiredService(); - var query = queryDiscovery.FindQuery(genericType); - controller.ControllerName = query.LowerCamelCaseName; - } - } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerFeatureProvider.cs b/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerFeatureProvider.cs deleted file mode 100644 index ff5f24a..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerFeatureProvider.cs +++ /dev/null @@ -1,51 +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; -using PoweredSoft.CQRS.DynamicQuery.Discover; - -namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc -{ - public class DynamicQueryControllerFeatureProvider : IApplicationFeatureProvider - { - private readonly ServiceProvider serviceProvider; - - public DynamicQueryControllerFeatureProvider(ServiceProvider serviceProvider) - { - this.serviceProvider = serviceProvider; - } - - public void PopulateFeature(IEnumerable parts, ControllerFeature feature) - { - var queryDiscovery = this.serviceProvider.GetRequiredService(); - foreach (var f in queryDiscovery.GetQueries()) - { - var ignoreAttribute = f.QueryType.GetCustomAttribute(); - if (ignoreAttribute != null) - continue; - - if (f.Category != "DynamicQuery") - continue; - - if (f is DynamicQueryMeta dynamicQueryMeta) - { - if (dynamicQueryMeta.ParamsType == null) - { - var controllerType = typeof(DynamicQueryController<,>).MakeGenericType(f.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType); - var controllerTypeInfo = controllerType.GetTypeInfo(); - feature.Controllers.Add(controllerTypeInfo); - } - else - { - var controllerType = typeof(DynamicQueryController<,,>).MakeGenericType(f.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType, dynamicQueryMeta.ParamsType); - var controllerTypeInfo = controllerType.GetTypeInfo(); - feature.Controllers.Add(controllerTypeInfo); - } - } - } - } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerOptions.cs b/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerOptions.cs deleted file mode 100644 index 35164b9..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/Mvc/DynamicQueryControllerOptions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc -{ - public class DynamicQueryControllerOptions - { - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/MvcBuilderExtensions.cs b/PoweredSoft.CQRS.DynamicQuery.AspNetCore/MvcBuilderExtensions.cs deleted file mode 100644 index bd809dd..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/MvcBuilderExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc; - -namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore -{ - public static class MvcBuilderExtensions - { - public static IMvcBuilder AddPoweredSoftDynamicQueries(this IMvcBuilder builder, Action 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; - } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/PoweredSoft.CQRS.DynamicQuery.AspNetCore.csproj b/PoweredSoft.CQRS.DynamicQuery.AspNetCore/PoweredSoft.CQRS.DynamicQuery.AspNetCore.csproj deleted file mode 100644 index 239a49c..0000000 --- a/PoweredSoft.CQRS.DynamicQuery.AspNetCore/PoweredSoft.CQRS.DynamicQuery.AspNetCore.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - net8.0 - Powered Softwares Inc. - https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro - PoweredSoft - PoweredSoft Team - true - - - - - - - - - - - - - - diff --git a/PoweredSoft.CQRS.DynamicQuery/Discover/DynamicQueryMeta.cs b/PoweredSoft.CQRS.DynamicQuery/Discover/DynamicQueryMeta.cs deleted file mode 100644 index de9034a..0000000 --- a/PoweredSoft.CQRS.DynamicQuery/Discover/DynamicQueryMeta.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Pluralize.NET; -using PoweredSoft.CQRS.Abstractions.Discovery; - -namespace PoweredSoft.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; } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery/DynamicQueryHandler.cs b/PoweredSoft.CQRS.DynamicQuery/DynamicQueryHandler.cs deleted file mode 100644 index 9dddab8..0000000 --- a/PoweredSoft.CQRS.DynamicQuery/DynamicQueryHandler.cs +++ /dev/null @@ -1,68 +0,0 @@ -using PoweredSoft.CQRS.DynamicQuery.Abstractions; -using PoweredSoft.DynamicQuery.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace PoweredSoft.CQRS.DynamicQuery -{ - public class DynamicQueryHandler - : DynamicQueryHandlerBase, - PoweredSoft.CQRS.Abstractions.IQueryHandler, IQueryExecutionResult> - where TSource : class - where TDestination : class - { - public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync, - IEnumerable> queryableProviders, - IEnumerable> alterQueryableServices, - IEnumerable> dynamicQueryInterceptorProviders, - IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, dynamicQueryInterceptorProviders, serviceProvider) - { - } - - public Task> HandleAsync(IDynamicQuery query, CancellationToken cancellationToken = default) - { - return ProcessQueryAsync(query, cancellationToken); - } - } - - public class DynamicQueryHandler - : DynamicQueryHandlerBase, - PoweredSoft.CQRS.Abstractions.IQueryHandler, IQueryExecutionResult> - where TSource : class - where TDestination : class - where TParams : class - { - private readonly IEnumerable> alterQueryableServicesWithParams; - - public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync, - IEnumerable> queryableProviders, - IEnumerable> alterQueryableServices, - IEnumerable> alterQueryableServicesWithParams, - IEnumerable> dynamicQueryInterceptorProviders, - IServiceProvider serviceProvider) : base(queryHandlerAsync, queryableProviders, alterQueryableServices, dynamicQueryInterceptorProviders, serviceProvider) - { - this.alterQueryableServicesWithParams = alterQueryableServicesWithParams; - } - - protected override async Task> AlterSourceAsync(IQueryable source, IDynamicQuery query, CancellationToken cancellationToken) - { - source = await base.AlterSourceAsync(source, query, cancellationToken); - - if (query is IDynamicQueryParams withParams) - { - foreach (var it in alterQueryableServicesWithParams) - source = await it.AlterQueryableAsync(source, withParams, cancellationToken); - } - - return source; - } - - public Task> HandleAsync(IDynamicQuery query, CancellationToken cancellationToken = default) - { - return this.ProcessQueryAsync(query, cancellationToken); - } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery/DynamicQueryHandlerBase.cs b/PoweredSoft.CQRS.DynamicQuery/DynamicQueryHandlerBase.cs deleted file mode 100644 index 7544861..0000000 --- a/PoweredSoft.CQRS.DynamicQuery/DynamicQueryHandlerBase.cs +++ /dev/null @@ -1,92 +0,0 @@ -using PoweredSoft.CQRS.DynamicQuery.Abstractions; -using PoweredSoft.DynamicQuery; -using PoweredSoft.DynamicQuery.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace PoweredSoft.CQRS.DynamicQuery -{ - public abstract class DynamicQueryHandlerBase - where TSource : class - where TDestination : class - { - private readonly IQueryHandlerAsync queryHandlerAsync; - private readonly IEnumerable> queryableProviders; - private readonly IEnumerable> alterQueryableServices; - private readonly IEnumerable> dynamicQueryInterceptorProviders; - private readonly IServiceProvider serviceProvider; - - public DynamicQueryHandlerBase(IQueryHandlerAsync queryHandlerAsync, - IEnumerable> queryableProviders, - IEnumerable> alterQueryableServices, - IEnumerable> dynamicQueryInterceptorProviders, - IServiceProvider serviceProvider) - { - this.queryHandlerAsync = queryHandlerAsync; - this.queryableProviders = queryableProviders; - this.alterQueryableServices = alterQueryableServices; - this.dynamicQueryInterceptorProviders = dynamicQueryInterceptorProviders; - this.serviceProvider = serviceProvider; - } - - protected virtual Task> GetQueryableAsync(IDynamicQuery query, CancellationToken cancellationToken = default) - { - if (this.queryableProviders.Any()) - return queryableProviders.ElementAt(0).GetQueryableAsync(query, cancellationToken); - - throw new Exception($"You must provide a QueryableProvider for {typeof(TSource).Name}"); - } - - public virtual IQueryExecutionOptions GetQueryExecutionOptions(IQueryable source, IDynamicQuery query) - { - return new QueryExecutionOptions(); - } - - public virtual IEnumerable GetInterceptors() - { - var types = dynamicQueryInterceptorProviders.SelectMany(t => t.GetInterceptorsTypes()).Distinct(); - foreach (var type in types) - yield return serviceProvider.GetService(type) as IQueryInterceptor; - } - - protected async Task> 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 = this.GetInterceptors(); - - foreach (var interceptor in interceptors) - queryHandlerAsync.AddInterceptor(interceptor); - - var criteria = CreateCriteriaFromQuery(query); - var result = await queryHandlerAsync.ExecuteAsync(source, criteria, options, cancellationToken); - return result; - } - - protected virtual async Task> AlterSourceAsync(IQueryable 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(), - Sorts = query?.GetSorts() ?? new List(), - Groups = query?.GetGroups() ?? new List(), - Aggregates = query?.GetAggregates() ?? new List() - }; - return criteria; - } - } -} diff --git a/PoweredSoft.CQRS.DynamicQuery/PoweredSoft.CQRS.DynamicQuery.csproj b/PoweredSoft.CQRS.DynamicQuery/PoweredSoft.CQRS.DynamicQuery.csproj deleted file mode 100644 index 87a95fa..0000000 --- a/PoweredSoft.CQRS.DynamicQuery/PoweredSoft.CQRS.DynamicQuery.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - netstandard2.1 - Powered Softwares Inc. - https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro - PoweredSoft - PoweredSoft Team - - - - - - - - - - - - diff --git a/PoweredSoft.CQRS.DynamicQuery/ServiceCollectionExtensions.cs b/PoweredSoft.CQRS.DynamicQuery/ServiceCollectionExtensions.cs deleted file mode 100644 index 12bdedb..0000000 --- a/PoweredSoft.CQRS.DynamicQuery/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,175 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using PoweredSoft.CQRS.Abstractions; -using PoweredSoft.CQRS.Abstractions.Discovery; -using PoweredSoft.CQRS.DynamicQuery.Abstractions; -using PoweredSoft.CQRS.DynamicQuery.Discover; -using PoweredSoft.DynamicQuery.Core; - -namespace PoweredSoft.CQRS.DynamicQuery -{ - public static class ServiceCollectionExtensions - { - public static IServiceCollection AddDynamicQuery(this IServiceCollection services, string name = null) - where TSourceAndDestination : class - => AddDynamicQuery(services, name: name); - - public static IServiceCollection AddDynamicQuery(this IServiceCollection services, string name = null) - where TSource : class - where TDestination : class - { - // add query handler. - services.AddTransient, IQueryExecutionResult>, DynamicQueryHandler>(); - - // add for discovery purposes. - var queryType = typeof(IDynamicQuery); - var resultType = typeof(IQueryExecutionResult); - var serviceType = typeof(DynamicQueryHandler); - var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType) - { - OverridableName = name - }; - - services.AddSingleton(queryMeta); - - return services; - } - - public static IServiceCollection AddDynamicQueryWithProvider(this IServiceCollection services, string name = null) - where TQueryableProvider : class, IQueryableProvider - where TSource : class - { - services.AddTransient, TQueryableProvider>() - .AddDynamicQuery(name: name); - return services; - } - - public static IServiceCollection AddDynamicQueryWithParamsAndProvider(this IServiceCollection services, string name = null) - where TQueryableProvider : class, IQueryableProvider - where TParams : class - where TSource : class - { - services.AddTransient, TQueryableProvider>() - .AddDynamicQueryWithParams(name: name); - return services; - } - - public static IServiceCollection AddDynamicQueryWithParams(this IServiceCollection services, string name = null) - where TSourceAndDestination : class - where TParams : class - => AddDynamicQueryWithParams(services, name: name); - - public static IServiceCollection AddDynamicQueryWithParams(this IServiceCollection services, string name = null) - where TSource : class - where TDestination : class - where TParams : class - { - // add query handler. - services.AddTransient, IQueryExecutionResult>, DynamicQueryHandler>(); - - // add for discovery purposes. - var queryType = typeof(IDynamicQuery); - var resultType = typeof(IQueryExecutionResult); - var serviceType = typeof(DynamicQueryHandler); - var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType) - { - - // params type. - ParamsType = typeof(TParams), - OverridableName = name - }; - - services.AddSingleton(queryMeta); - - return services; - } - - public static IServiceCollection AddAlterQueryable(this IServiceCollection services) - where TService : class, IAlterQueryableService - { - return services.AddTransient, TService>(); - } - - public static IServiceCollection AddAlterQueryable(this IServiceCollection services) - where TService : class, IAlterQueryableService - { - return services.AddTransient, TService>(); - } - - public static IServiceCollection AddAlterQueryableWithParams - (this IServiceCollection services) - where TParams : class - where TService : class, IAlterQueryableService - { - return services.AddTransient, TService>(); - } - - public static IServiceCollection AddAlterQueryableWithParams - (this IServiceCollection services) - where TParams : class - where TService : class, IAlterQueryableService - { - return services.AddTransient, TService>(); - } - - public static IServiceCollection AddDynamicQueryInterceptor(this IServiceCollection services) - where TInterceptor : class, IQueryInterceptor - { - services.TryAddTransient(); - return services.AddSingleton>( - new DynamicQueryInterceptorProvider(typeof(TInterceptor))); - } - - public static IServiceCollection AddDynamicQueryInterceptors(this IServiceCollection services) - where T1 : class, IQueryInterceptor - where T2 : class, IQueryInterceptor - { - services.TryAddTransient(); - services.TryAddTransient(); - return services.AddSingleton>( - new DynamicQueryInterceptorProvider(typeof(T1), typeof(T2))); - } - - public static IServiceCollection AddDynamicQueryInterceptors(this IServiceCollection services) - where T1 : class, IQueryInterceptor - where T2 : class, IQueryInterceptor - where T3 : class, IQueryInterceptor - { - services.TryAddTransient(); - services.TryAddTransient(); - services.TryAddTransient(); - return services.AddSingleton>( - new DynamicQueryInterceptorProvider(typeof(T1), typeof(T2), typeof(T3))); - } - - public static IServiceCollection AddDynamicQueryInterceptors(this IServiceCollection services) - where T1 : class, IQueryInterceptor - where T2 : class, IQueryInterceptor - where T3 : class, IQueryInterceptor - where T4 : class, IQueryInterceptor - { - services.TryAddTransient(); - services.TryAddTransient(); - services.TryAddTransient(); - services.TryAddTransient(); - return services.AddSingleton>( - new DynamicQueryInterceptorProvider(typeof(T1), typeof(T2), typeof(T3), typeof(T4))); - } - - public static IServiceCollection AddDynamicQueryInterceptors(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(); - services.TryAddTransient(); - services.TryAddTransient(); - services.TryAddTransient(); - services.TryAddTransient(); - return services.AddSingleton>( - new DynamicQueryInterceptorProvider(typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5))); - } - } -} diff --git a/PoweredSoft.CQRS.FluentValidation/PoweredSoft.CQRS.FluentValidation.csproj b/PoweredSoft.CQRS.FluentValidation/PoweredSoft.CQRS.FluentValidation.csproj deleted file mode 100644 index ead9b61..0000000 --- a/PoweredSoft.CQRS.FluentValidation/PoweredSoft.CQRS.FluentValidation.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - netstandard2.1 - Powered Softwares Inc. - https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro - PoweredSoft - PoweredSoft Team - - - - - - - - - - diff --git a/PoweredSoft.CQRS.FluentValidation/ServiceCollectionExtensions.cs b/PoweredSoft.CQRS.FluentValidation/ServiceCollectionExtensions.cs deleted file mode 100644 index 85172eb..0000000 --- a/PoweredSoft.CQRS.FluentValidation/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using FluentValidation; -using Microsoft.Extensions.DependencyInjection; -using PoweredSoft.CQRS.Abstractions; - -namespace PoweredSoft.CQRS.FluentValidation -{ - public static class ServiceCollectionExtensions - { - private static IServiceCollection AddFluentValidator(this IServiceCollection services) - where TValidator : class, IValidator - { - services.AddTransient, TValidator>(); - return services; - } - - public static IServiceCollection AddCommand(this IServiceCollection services) - where TCommand : class - where TCommandHandler : class, ICommandHandler - where TValidator : class, IValidator - { - return services.AddCommand() - .AddFluentValidator(); - } - - public static IServiceCollection AddCommand(this IServiceCollection services) - where TCommand : class - where TCommandHandler : class, ICommandHandler - where TValidator : class, IValidator - { - return services.AddCommand() - .AddFluentValidator(); - } - - public static IServiceCollection AddQuery(this IServiceCollection services) - where TQuery : class - where TQueryHandler : class, IQueryHandler - where TValidator : class, IValidator - { - services.AddQuery() - .AddFluentValidator(); - return services; - } - } -} diff --git a/PoweredSoft.CQRS/Discovery/CommandDiscovery.cs b/PoweredSoft.CQRS/Discovery/CommandDiscovery.cs deleted file mode 100644 index ffc7d21..0000000 --- a/PoweredSoft.CQRS/Discovery/CommandDiscovery.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using PoweredSoft.CQRS.Abstractions.Discovery; - -namespace PoweredSoft.CQRS.Discovery -{ - public class CommandDiscovery : ICommandDiscovery - { - private readonly IEnumerable commandMetas; - - public CommandDiscovery(IEnumerable commandMetas) - { - this.commandMetas = commandMetas; - } - - public virtual IEnumerable GetCommands() => commandMetas; - public virtual ICommandMeta FindCommand(string name) => commandMetas.FirstOrDefault(t => t.Name == name); - public virtual ICommandMeta FindCommand(Type commandType) => commandMetas.FirstOrDefault(t => t.CommandType == commandType); - public virtual bool CommandExists(string name) => commandMetas.Any(t => t.Name == name); - public virtual bool CommandExists(Type commandType) => commandMetas.Any(t => t.CommandType == commandType); - } -} diff --git a/PoweredSoft.CQRS/Discovery/QueryDiscovery.cs b/PoweredSoft.CQRS/Discovery/QueryDiscovery.cs deleted file mode 100644 index e2240da..0000000 --- a/PoweredSoft.CQRS/Discovery/QueryDiscovery.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using PoweredSoft.CQRS.Abstractions.Discovery; - -namespace PoweredSoft.CQRS.Discovery -{ - public class QueryDiscovery : IQueryDiscovery - { - private readonly IEnumerable queryMetas; - - public QueryDiscovery(IEnumerable queryMetas) - { - this.queryMetas = queryMetas; - } - - public virtual IEnumerable GetQueries() => queryMetas; - public virtual IQueryMeta FindQuery(string name) => queryMetas.FirstOrDefault(t => t.Name == name); - public virtual IQueryMeta FindQuery(Type queryType) => queryMetas.FirstOrDefault(t => t.QueryType == queryType); - public virtual bool QueryExists(string name) => queryMetas.Any(t => t.Name == name); - public virtual bool QueryExists(Type queryType) => queryMetas.Any(t => t.QueryType == queryType); - } -} diff --git a/PoweredSoft.CQRS/PoweredSoft.CQRS.csproj b/PoweredSoft.CQRS/PoweredSoft.CQRS.csproj deleted file mode 100644 index e8d4611..0000000 --- a/PoweredSoft.CQRS/PoweredSoft.CQRS.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - netstandard2.1 - Powered Softwares Inc. - https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;r=g&amp;d=retro - PoweredSoft - PoweredSoft Team - - - - - - diff --git a/PoweredSoft.CQRS/ServiceCollectionExtensions.cs b/PoweredSoft.CQRS/ServiceCollectionExtensions.cs deleted file mode 100644 index 57b1356..0000000 --- a/PoweredSoft.CQRS/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using PoweredSoft.CQRS.Abstractions.Discovery; -using PoweredSoft.CQRS.Discovery; - -namespace PoweredSoft.CQRS -{ - public static class ServiceCollectionExtensions - { - public static IServiceCollection AddDefaultQueryDiscovery(this IServiceCollection services) - { - services.TryAddTransient(); - return services; - } - - public static IServiceCollection AddDefaultCommandDiscovery(this IServiceCollection services) - { - services.TryAddTransient(); - return services; - } - } -}