initial commit for .net 8 migration

This commit is contained in:
Mathias Beaulieu-Duncan 2023-10-02 11:25:45 -04:00
parent 9015dc2d5f
commit 88c86513e9
105 changed files with 133 additions and 2172 deletions

View File

@ -1,54 +0,0 @@
using PoweredSoft.Data.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.AsyncProvider
{
public class InMemoryQueryableHandler : IAsyncQueryableHandlerService
{
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.Any(predicate));
}
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.Any());
}
public bool CanHandle<T>(IQueryable<T> queryable)
{
var result = queryable is EnumerableQuery<T>;
return result;
}
public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.Count());
}
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.FirstOrDefault());
}
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.FirstOrDefault(predicate));
}
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.LongCount());
}
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.ToList());
}
}
}

View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo.Commands
{
public class CreatePersonCommand
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}

View File

@ -1,14 +0,0 @@
using PoweredSoft.CQRS.Abstractions;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.Commands
{
public class CreatePersonCommandHandler : ICommandHandler<CreatePersonCommand>
{
public Task HandleAsync(CreatePersonCommand command, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
}
}

View File

@ -1,13 +0,0 @@
using FluentValidation;
namespace Demo.Commands
{
public class CreatePersonCommandValidator : AbstractValidator<CreatePersonCommand>
{
public CreatePersonCommandValidator()
{
RuleFor(t => t.FirstName).NotEmpty();
RuleFor(t => t.LastName).NotEmpty();
}
}
}

View File

@ -1,31 +0,0 @@
using FluentValidation;
using PoweredSoft.CQRS.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.Commands
{
public class EchoCommand
{
public string Message { get; set; }
}
public class EchoCommandValidator : AbstractValidator<EchoCommand>
{
public EchoCommandValidator()
{
RuleFor(t => t.Message).NotEmpty();
}
}
public class EchoCommandHandler : ICommandHandler<EchoCommand, string>
{
public Task<string> HandleAsync(EchoCommand command, CancellationToken cancellationToken = default)
{
return Task.FromResult(command.Message);
}
}
}

View File

@ -1,30 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation.AspNetCore" Version="10.3.0" />
<PackageReference Include="HotChocolate.AspNetCore" Version="11.3.4" />
<PackageReference Include="Microsoft.AspNetCore.OData" Version="8.0.1" />
<PackageReference Include="PoweredSoft.Data" Version="3.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.1.5" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.1.5" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.1.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PoweredSoft.CQRS.AspNetCore\PoweredSoft.CQRS.AspNetCore.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery.Abstractions\PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery.AspNetCore\PoweredSoft.CQRS.DynamicQuery.AspNetCore.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery\PoweredSoft.CQRS.DynamicQuery.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.FluentValidation\PoweredSoft.CQRS.FluentValidation.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.GraphQL.FluentValidation\PoweredSoft.CQRS.GraphQL.FluentValidation.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.GraphQL.HotChocolate.DynamicQuery\PoweredSoft.CQRS.GraphQL.HotChocolate.DynamicQuery.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.GraphQL.HotChocolate\PoweredSoft.CQRS.GraphQL.HotChocolate.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS\PoweredSoft.CQRS.csproj" />
</ItemGroup>
</Project>

View File

@ -1,15 +0,0 @@
using System;
namespace Demo.DynamicQueries
{
public class Contact
{
public long Id { get; set; }
public string DisplayName { get; set; }
}
public class SearchContactParams
{
public string SearchDisplayName { get; set; }
}
}

View File

@ -1,23 +0,0 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.DynamicQueries
{
public class ContactQueryableProvider : IQueryableProvider<Contact>
{
public Task<IQueryable<Contact>> GetQueryableAsync(object query, CancellationToken cancelllationToken = default)
{
var source = new List<Contact>
{
new Contact { Id = 1, DisplayName = "David L"},
new Contact { Id = 2, DisplayName = "John Doe"}
};
var ret = source.AsQueryable();
return Task.FromResult(ret);
}
}
}

View File

@ -1,18 +0,0 @@
using Demo.Queries;
using PoweredSoft.DynamicQuery.Core;
using System.Linq;
namespace Demo.DynamicQueries
{
public class PersonConvertInterceptor : IQueryConvertInterceptor<Person, PersonModel>
{
public PersonModel InterceptResultTo(Person entity)
{
return new PersonModel
{
Id = entity.Id,
FullName = entity.FirstName + " " + entity.LastName
};
}
}
}

View File

@ -1,10 +0,0 @@
using System;
namespace Demo.DynamicQueries
{
public class PersonModel
{
public long Id { get; set; }
public string FullName { get; set; }
}
}

View File

@ -1,54 +0,0 @@
using Demo.Queries;
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System.Collections.Generic;
namespace Demo.DynamicQueries
{
public class PersonOptimizationInterceptor : IFilterInterceptor, ISortInterceptor
{
public IFilter InterceptFilter(IFilter filter)
{
if (filter is ISimpleFilter simpleFilter)
{
if (simpleFilter.Path.Equals(nameof(PersonModel.FullName), System.StringComparison.InvariantCultureIgnoreCase))
return new CompositeFilter
{
Type = filter.Type,
And = filter.And,
Filters = new List<IFilter> {
new SimpleFilter
{
Not = simpleFilter.Not,
And = false,
Type = simpleFilter.Type,
Value = simpleFilter.Value,
Path = nameof(Person.FirstName)
},
new SimpleFilter
{
Not = simpleFilter.Not,
And = false,
Type = simpleFilter.Type,
Value = simpleFilter.Value,
Path = nameof(Person.LastName)
}
}
};
}
return filter;
}
public IEnumerable<ISort> InterceptSort(IEnumerable<ISort> sort)
{
foreach(var s in sort)
{
if (s.Path.Equals(nameof(PersonModel.FullName), System.StringComparison.InvariantCultureIgnoreCase))
yield return new Sort(nameof(Person.LastName), s.Ascending);
else
yield return s;
}
}
}
}

View File

@ -1,33 +0,0 @@
using Demo.Queries;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.DynamicQueries
{
public class PersonQueryableProvider : IQueryableProvider<Person>
{
private readonly IEnumerable<Person> _persons = new List<Person>()
{
new Person
{
Id = 1,
FirstName = "David",
LastName = "Lebee"
},
new Person
{
Id = 2,
FirstName = "John",
LastName = "Doe"
}
};
public Task<IQueryable<Person>> GetQueryableAsync(object query, CancellationToken cancelllationToken = default)
{
return Task.FromResult(_persons.AsQueryable());
}
}
}

View File

@ -1,19 +0,0 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.DynamicQueries
{
public class SearchContactParamsService : IAlterQueryableService<Contact, Contact, SearchContactParams>
{
public Task<IQueryable<Contact>> AlterQueryableAsync(IQueryable<Contact> query, IDynamicQueryParams<SearchContactParams> dynamicQuery, CancellationToken cancellationToken = default)
{
var safe = dynamicQuery.GetParams()?.SearchDisplayName;
if (!string.IsNullOrEmpty(safe))
return Task.FromResult(query.Where(t => t.DisplayName.Contains(safe)));
return Task.FromResult(query);
}
}
}

View File

@ -1,26 +0,0 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Demo
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

View File

@ -1,28 +0,0 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:52483",
"sslPort": 44343
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Demo": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -1,32 +0,0 @@
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.Queries
{
public class OnePersonQuery
{
public long PersonId { get; set; }
}
public class OnePersonQueryHandler : IQueryHandler<OnePersonQuery, Person>
{
private readonly IQueryableProvider<Person> provider;
public OnePersonQueryHandler(IQueryableProvider<Person> provider)
{
this.provider = provider;
}
public async Task<Person> HandleAsync(OnePersonQuery query, CancellationToken cancellationToken = default)
{
var _ = await provider.GetQueryableAsync(query, cancellationToken);
var ret = _.First(t => t.Id == query.PersonId);
return ret;
}
}
}

View File

@ -1,39 +0,0 @@
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.Queries
{
public class ListPersonQuery
{
public string Search { get; set; }
}
public class ListPersonQueryHandler : IQueryHandler<ListPersonQuery, List<Person>>
{
private readonly IQueryableProvider<Person> provider;
public ListPersonQueryHandler(IQueryableProvider<Person> provider)
{
this.provider = provider;
}
public async Task<List<Person>> HandleAsync(ListPersonQuery query, CancellationToken cancellationToken = default)
{
var _ = await provider.GetQueryableAsync(query, cancellationToken);
if (query.Search != null)
_ = _
.Where(t => t.FirstName.Contains(query.Search, StringComparison.InvariantCultureIgnoreCase) ||
t.LastName.Contains(query.Search, StringComparison.InvariantCultureIgnoreCase));
var ret = _.ToList();
return ret;
}
}
}

View File

@ -1,16 +0,0 @@
using System.Collections.Generic;
namespace Demo.Queries
{
public class Person
{
public long Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class PersonQuery
{
public string Search { get; set; }
}
}

View File

@ -1,29 +0,0 @@
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.Queries
{
public class PersonQueryHandler : IQueryHandler<PersonQuery, IQueryable<Person>>
{
private readonly IQueryableProvider<Person> queryableProvider;
public PersonQueryHandler(IQueryableProvider<Person> queryableProvider)
{
this.queryableProvider = queryableProvider;
}
public async Task<IQueryable<Person>> HandleAsync(PersonQuery query, CancellationToken cancellationToken = default)
{
var ret = await queryableProvider.GetQueryableAsync(query);
if (query != null && !string.IsNullOrEmpty(query.Search))
ret = ret.Where(t => t.FirstName.Contains(query.Search) || t.LastName.Contains(query.Search));
return ret;
}
}
}

View File

@ -1,31 +0,0 @@
using Microsoft.AspNetCore.Http;
using PoweredSoft.CQRS.Abstractions.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.Security
{
public class CommandAndQueryAuthorizationService : IQueryAuthorizationService, ICommandAuthorizationService
{
private readonly IHttpContextAccessor httpContextAccessor;
public CommandAndQueryAuthorizationService(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public Task<AuthorizationResult> IsAllowedAsync(Type queryOrCommandType, CancellationToken cancellationToken = default)
{
var authResult = httpContextAccessor.HttpContext.Request.Query["auth-result"].FirstOrDefault();
if (authResult == "Unauthorized")
return Task.FromResult(AuthorizationResult.Unauthorized);
else if (authResult == "Forbidden")
return Task.FromResult(AuthorizationResult.Forbidden);
return Task.FromResult(AuthorizationResult.Allowed);
}
}
}

View File

@ -1,145 +0,0 @@
using Demo.AsyncProvider;
using Demo.Commands;
using Demo.DynamicQueries;
using Demo.Queries;
using FluentValidation;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using PoweredSoft.CQRS;
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.AspNetCore.Mvc;
using PoweredSoft.CQRS.DynamicQuery;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.CQRS.DynamicQuery.AspNetCore;
using PoweredSoft.CQRS.GraphQL.FluentValidation;
using PoweredSoft.CQRS.GraphQL.HotChocolate;
using PoweredSoft.Data;
using PoweredSoft.Data.Core;
using PoweredSoft.DynamicQuery;
using System.Linq;
using PoweredSoft.CQRS.GraphQL.HotChocolate.DynamicQuery;
using PoweredSoft.CQRS.Abstractions.Security;
using Demo.Security;
using PoweredSoft.CQRS.FluentValidation;
using Microsoft.AspNetCore.OData;
using System.Collections.Generic;
namespace Demo
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
AddQueries(services);
AddDynamicQueries(services);
AddCommands(services);
services.AddHttpContextAccessor();
services.AddTransient<IQueryAuthorizationService, CommandAndQueryAuthorizationService>();
services.AddTransient<ICommandAuthorizationService, CommandAndQueryAuthorizationService>();
services.AddTransient<IAsyncQueryableHandlerService, InMemoryQueryableHandler>();
services.AddPoweredSoftDataServices();
services.AddPoweredSoftDynamicQuery();
services.AddPoweredSoftCQRS();
services
.AddControllers()
.AddPoweredSoftQueries()
.AddPoweredSoftCommands()
.AddPoweredSoftDynamicQueries()
.AddFluentValidation();
services
.AddGraphQLServer()
.AddProjections()
.AddQueryType(d => d.Name("Query"))
.AddPoweredSoftQueries()
.AddPoweredSoftDynamicQueries()
.AddMutationType(d => d.Name("Mutation"))
.AddPoweredSoftMutations();
services.AddPoweredSoftGraphQLFluentValidation();
services.AddSwaggerGen();
services.AddCors();
}
private void AddDynamicQueries(IServiceCollection services)
{
services.AddTransient<IQueryableProvider<Contact>, ContactQueryableProvider>();
services.AddDynamicQuery<Contact>();
services.AddDynamicQueryWithParams<Contact, SearchContactParams>(name: "SearchContacts")
.AddAlterQueryableWithParams<Contact, SearchContactParams, SearchContactParamsService>();
services
.AddTransient<IQueryableProvider<Person>, PersonQueryableProvider>()
.AddDynamicQuery<Person, PersonModel>(name: "People")
.AddDynamicQueryInterceptors<Person, PersonModel, PersonConvertInterceptor, PersonOptimizationInterceptor>();
}
private void AddCommands(IServiceCollection services)
{
services.AddCommand<CreatePersonCommand, CreatePersonCommandHandler>();
services.AddTransient<IValidator<CreatePersonCommand>, CreatePersonCommandValidator>();
/* OLD WAY STILL VALID
services.AddCommand<EchoCommand, string, EchoCommandHandler>();
services.AddTransient<IValidator<EchoCommand>, EchoCommandValidator>();*/
// new way :) with PoweredSoft.CQRS.FluentValidation package.
services.AddCommandWithValidator<EchoCommand, string, EchoCommandHandler, EchoCommandValidator>();
}
private void AddQueries(IServiceCollection services)
{
services.AddQuery<PersonQuery, IQueryable<Person>, PersonQueryHandler>();
services.AddQuery<OnePersonQuery, Person, OnePersonQueryHandler>();
services.AddQuery<ListPersonQuery, List<Person>, ListPersonQueryHandler>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseCors(o => o.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
app.UseRouting();
app.UseAuthorization();
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapGraphQL();
});
}
}
}

View File

@ -1,9 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@ -1,10 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

View File

@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.Abstractions.Attributes
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class CommandNameAttribute : Attribute
{
public CommandNameAttribute(string name)

View File

@ -2,7 +2,7 @@
namespace PoweredSoft.CQRS.Abstractions.Attributes
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class QueryNameAttribute : Attribute
{
public QueryNameAttribute(string name)

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.Abstractions.Discovery
{

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace PoweredSoft.CQRS.Abstractions.Discovery
{

View File

@ -1,16 +1,15 @@
using System;
using System.Threading;
using System.Threading;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.Abstractions
{
public interface ICommandHandler<TCommand>
public interface ICommandHandler<in TCommand>
where TCommand : class
{
Task HandleAsync(TCommand command, CancellationToken cancellationToken = default);
}
public interface ICommandHandler<TCommand, TCommandResult>
public interface ICommandHandler<in TCommand, TCommandResult>
where TCommand : class
{
Task<TCommandResult> HandleAsync(TCommand command, CancellationToken cancellationToken = default);

View File

@ -3,7 +3,7 @@ using System.Threading.Tasks;
namespace PoweredSoft.CQRS.Abstractions
{
public interface IQueryHandler<TQuery, TQueryResult>
public interface IQueryHandler<in TQuery, TQueryResult>
where TQuery : class
{
Task<TQueryResult> HandleAsync(TQuery query, CancellationToken cancellationToken = default);

View File

@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
<Authors>PoweredSoft Team</Authors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0-rc.1.23419.4" />
</ItemGroup>
</Project>

View File

@ -1,8 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.Abstractions.Discovery;
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.Abstractions
{

View File

@ -2,7 +2,7 @@
namespace PoweredSoft.CQRS.AspNetCore.Abstractions.Attributes
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class CommandControllerIgnoreAttribute : Attribute
{
}

View File

@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.AspNetCore.Abstractions.Attributes
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class QueryControllerIgnoreAttribute : Attribute
{
}

View File

@ -1,11 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
<Authors>PoweredSoft Team</Authors>
</PropertyGroup>
</Project>

View File

@ -1,9 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using PoweredSoft.CQRS.Abstractions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.AspNetCore.Mvc
{

View File

@ -11,16 +11,16 @@ namespace PoweredSoft.CQRS.AspNetCore.Mvc
{
public class CommandControllerAsyncAuthorizationFilter : IAsyncAuthorizationFilter
{
private readonly ICommandAuthorizationService _authorizationService;
private readonly ICommandAuthorizationService authorizationService;
public CommandControllerAsyncAuthorizationFilter(IServiceProvider serviceProvider)
{
_authorizationService = serviceProvider.GetService<ICommandAuthorizationService>();
authorizationService = serviceProvider.GetService<ICommandAuthorizationService>();
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (_authorizationService == null)
if (authorizationService == null)
return;
var action = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
@ -34,7 +34,7 @@ namespace PoweredSoft.CQRS.AspNetCore.Mvc
else
commandType = action.ControllerTypeInfo.GenericTypeArguments.First();
var ar = await _authorizationService.IsAllowedAsync(commandType);
var ar = await authorizationService.IsAllowedAsync(commandType);
if (ar == AuthorizationResult.Forbidden)
context.Result = new StatusCodeResult(403);
else if(ar == AuthorizationResult.Unauthorized)

View File

@ -16,8 +16,15 @@ namespace PoweredSoft.CQRS.AspNetCore.Mvc
public void Apply(ControllerModel controller)
{
if (controller.ControllerType.IsGenericType && controller.ControllerType.Name.Contains("CommandController") && controller.ControllerType.Assembly == typeof(CommandControllerConvention).Assembly)
{
if (!controller.ControllerType.IsGenericType)
return;
if (!controller.ControllerType.Name.Contains("CommandController"))
return;
if (controller.ControllerType.Assembly != typeof(CommandControllerConvention).Assembly)
return;
var genericType = controller.ControllerType.GenericTypeArguments[0];
var commandDiscovery = this.serviceProvider.GetRequiredService<ICommandDiscovery>();
var command = commandDiscovery.FindCommand(genericType);
@ -25,4 +32,3 @@ namespace PoweredSoft.CQRS.AspNetCore.Mvc
}
}
}
}

View File

@ -1,12 +1,10 @@
using Microsoft.AspNetCore.Mvc.ApplicationParts;
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 System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace PoweredSoft.CQRS.AspNetCore.Mvc
{

View File

@ -1,9 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using PoweredSoft.CQRS.Abstractions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.AspNetCore.Mvc
{

View File

@ -11,16 +11,16 @@ namespace PoweredSoft.CQRS.AspNetCore.Mvc
{
public class QueryControllerAsyncAuthorizationFilter : IAsyncAuthorizationFilter
{
private readonly IQueryAuthorizationService _authorizationService;
private readonly IQueryAuthorizationService authorizationService;
public QueryControllerAsyncAuthorizationFilter(IServiceProvider serviceProvider)
{
_authorizationService = serviceProvider.GetService<IQueryAuthorizationService>();
authorizationService = serviceProvider.GetService<IQueryAuthorizationService>();
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (_authorizationService == null)
if (authorizationService == null)
return;
var action = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
@ -34,7 +34,7 @@ namespace PoweredSoft.CQRS.AspNetCore.Mvc
else
queryType = action.ControllerTypeInfo.GenericTypeArguments.First();
var ar = await _authorizationService.IsAllowedAsync(queryType);
var ar = await authorizationService.IsAllowedAsync(queryType);
if (ar == AuthorizationResult.Forbidden)
context.Result = new StatusCodeResult(403);
else if (ar == AuthorizationResult.Unauthorized)

View File

@ -1,12 +1,10 @@
using Microsoft.AspNetCore.Mvc.ApplicationParts;
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 System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace PoweredSoft.CQRS.AspNetCore.Mvc
{

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.AspNetCore.Mvc
namespace PoweredSoft.CQRS.AspNetCore.Mvc
{
public class QueryControllerOptions
{

View File

@ -1,11 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
<TargetFramework>net8.0</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
<Authors>PoweredSoft Team</Authors>
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>
<ItemGroup>

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

View File

@ -1,7 +1,5 @@
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Generic;
using PoweredSoft.DynamicQuery.Core;
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
{
@ -12,7 +10,7 @@ namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
}
public interface IDynamicQuery<TSource, TDestination, TParams> : IDynamicQuery<TSource, TDestination>, IDynamicQueryParams<TParams>
public interface IDynamicQuery<TSource, TDestination, out TParams> : IDynamicQuery<TSource, TDestination>, IDynamicQueryParams<TParams>
where TSource : class
where TDestination : class
where TParams : class
@ -21,7 +19,6 @@ namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
}
public interface IDynamicQuery
{
List<IFilter> GetFilters();
List<IGroup> GetGroups();

View File

@ -1,7 +1,5 @@
using PoweredSoft.DynamicQuery.Core;
using System;
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
{

View File

@ -1,6 +1,6 @@
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
{
public interface IDynamicQueryParams<TParams>
public interface IDynamicQueryParams<out TParams>
where TParams : class
{
TParams GetParams();

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -9,6 +6,6 @@ namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
{
public interface IQueryableProvider<TSource>
{
Task<IQueryable<TSource>> GetQueryableAsync(object query, CancellationToken cancelllationToken = default);
Task<IQueryable<TSource>> GetQueryableAsync(object query, CancellationToken cancellationToken = default);
}
}

View File

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
@ -11,5 +10,4 @@
<ItemGroup>
<PackageReference Include="PoweredSoft.DynamicQuery.Core" Version="3.0.1" />
</ItemGroup>
</Project>

View File

@ -1,10 +1,8 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System.Collections.Generic;
using System.Linq;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
{

View File

@ -1,10 +1,10 @@
using Microsoft.AspNetCore.Mvc;
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System;
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
{
@ -49,18 +49,29 @@ namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
object value = Value;
if (Value is JsonElement jsonElement)
{
if (jsonElement.ValueKind == JsonValueKind.String)
switch (jsonElement.ValueKind)
{
case JsonValueKind.String:
value = jsonElement.ToString();
else if (jsonElement.ValueKind == JsonValueKind.Number && jsonElement.TryGetInt64(out var l))
value = l;
else if (jsonElement.ValueKind == JsonValueKind.True)
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;
else if (jsonElement.ValueKind == JsonValueKind.False)
break;
case JsonValueKind.False:
value = false;
else if (jsonElement.ValueKind == JsonValueKind.Array)
throw new System.Exception("TODO");
else
break;
// TODO: Array support
default:
value = null;
break;
}
}
var simpleFilter = new SimpleFilter

View File

@ -1,23 +1,21 @@
using Microsoft.AspNetCore.Mvc;
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;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
{
[ApiController, Route("api/query/[controller]")]
public class DynamicQueryController<TUnderlyingQuery, TSource, TDestination> : Controller
public class DynamicQueryController<TSource, TDestination> : Controller
where TSource : class
where TDestination : class
{
[HttpPost, QueryControllerAuthorization]
public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
[FromBody] DynamicQuery<TSource, TDestination> query,
[FromServices]PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
[FromServices]IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
)
{
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
@ -27,7 +25,7 @@ namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
[HttpGet, QueryControllerAuthorization]
public async Task<IQueryExecutionResult<TDestination>> HandleGetAsync(
[FromQuery] DynamicQuery<TSource, TDestination> query,
[FromServices] PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
[FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
)
{
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
@ -36,7 +34,7 @@ namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
}
[ApiController, Route("api/query/[controller]")]
public class DynamicQueryController<TUnderlyingQuery, TSource, TDestination, TParams> : Controller
public class DynamicQueryController<TSource, TDestination, TParams> : Controller
where TSource : class
where TDestination : class
where TParams : class
@ -44,7 +42,7 @@ namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
[HttpPost, QueryControllerAuthorization]
public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
[FromBody] DynamicQuery<TSource, TDestination, TParams> query,
[FromServices] PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
[FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
)
{
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
@ -54,7 +52,7 @@ namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
[HttpGet, QueryControllerAuthorization]
public async Task<IQueryExecutionResult<TDestination>> HandleGetAsync(
[FromQuery] DynamicQuery<TSource, TDestination, TParams> query,
[FromServices] PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
[FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
)
{
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);

View File

@ -1,9 +1,7 @@
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.Abstractions.Discovery;
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
{

View File

@ -1,13 +1,11 @@
using Microsoft.AspNetCore.Mvc.ApplicationParts;
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;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
{
@ -36,13 +34,13 @@ namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
{
if (dynamicQueryMeta.ParamsType == null)
{
var controllerType = typeof(DynamicQueryController<,,>).MakeGenericType(f.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType);
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 controllerType = typeof(DynamicQueryController<,,>).MakeGenericType(f.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType, dynamicQueryMeta.ParamsType);
var controllerTypeInfo = controllerType.GetTypeInfo();
feature.Controllers.Add(controllerTypeInfo);
}

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
{
public class DynamicQueryControllerOptions
{

View File

@ -1,11 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System;
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc;
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
{

View File

@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
<TargetFramework>net8.0</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
<Authors>PoweredSoft Team</Authors>
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>
<ItemGroup>
@ -19,5 +19,4 @@
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery.Abstractions\PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery\PoweredSoft.CQRS.DynamicQuery.csproj" />
</ItemGroup>
</Project>

View File

@ -1,8 +1,6 @@
using PoweredSoft.CQRS.Abstractions.Discovery;
using PoweredSoft.CQRS.Discovery;
using System;
using System.Collections.Generic;
using System.Text;
using System;
using Pluralize.NET;
using PoweredSoft.CQRS.Abstractions.Discovery;
namespace PoweredSoft.CQRS.DynamicQuery.Discover
{
@ -23,7 +21,7 @@ namespace PoweredSoft.CQRS.DynamicQuery.Discover
if (OverridableName != null)
return OverridableName;
var pluralizer = new Pluralize.NET.Pluralizer();
var pluralizer = new Pluralizer();
return pluralizer.Pluralize(DestinationType.Name);
}
}

View File

@ -83,8 +83,8 @@ namespace PoweredSoft.CQRS.DynamicQuery
PageSize = query?.GetPageSize(),
Filters = query?.GetFilters() ?? new List<IFilter>(),
Sorts = query?.GetSorts() ?? new List<ISort>(),
Groups = query.GetGroups() ?? new List<IGroup>(),
Aggregates = query.GetAggregates() ?? new List<IAggregate>()
Groups = query?.GetGroups() ?? new List<IGroup>(),
Aggregates = query?.GetAggregates() ?? new List<IAggregate>()
};
return criteria;
}

View File

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
@ -17,5 +16,4 @@
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery.Abstractions\PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS\PoweredSoft.CQRS.csproj" />
</ItemGroup>
</Project>

View File

@ -5,9 +5,6 @@ using PoweredSoft.CQRS.Abstractions.Discovery;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.CQRS.DynamicQuery.Discover;
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery
{
@ -22,7 +19,7 @@ namespace PoweredSoft.CQRS.DynamicQuery
where TDestination : class
{
// add query handler.
services.AddTransient<PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination>>();
services.AddTransient<IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination>>();
// add for discovery purposes.
var queryType = typeof(IDynamicQuery<TSource, TDestination>);
@ -68,7 +65,7 @@ namespace PoweredSoft.CQRS.DynamicQuery
where TParams : class
{
// add query handler.
services.AddTransient<PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination, TParams>>();
services.AddTransient<IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination, TParams>>();
// add for discovery purposes.
var queryType = typeof(IDynamicQuery<TSource, TDestination, TParams>);

View File

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
@ -9,11 +8,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="10.3.0" />
<PackageReference Include="FluentValidation" Version="10.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PoweredSoft.CQRS\PoweredSoft.CQRS.csproj" />
</ItemGroup>
</Project>

View File

@ -1,12 +1,6 @@
using FluentValidation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.Abstractions.Discovery;
using PoweredSoft.CQRS.Discovery;
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.FluentValidation
{
@ -19,7 +13,7 @@ namespace PoweredSoft.CQRS.FluentValidation
return services;
}
public static IServiceCollection AddCommandWithValidator<TCommand, TCommandHandler, TValidator>(this IServiceCollection services)
public static IServiceCollection AddCommand<TCommand, TCommandHandler, TValidator>(this IServiceCollection services)
where TCommand : class
where TCommandHandler : class, ICommandHandler<TCommand>
where TValidator : class, IValidator<TCommand>
@ -28,7 +22,7 @@ namespace PoweredSoft.CQRS.FluentValidation
.AddFluentValidator<TCommand, TValidator>();
}
public static IServiceCollection AddCommandWithValidator<TCommand, TCommandResult, TCommandHandler, TValidator>(this IServiceCollection services)
public static IServiceCollection AddCommand<TCommand, TCommandResult, TCommandHandler, TValidator>(this IServiceCollection services)
where TCommand : class
where TCommandHandler : class, ICommandHandler<TCommand, TCommandResult>
where TValidator : class, IValidator<TCommand>
@ -37,7 +31,7 @@ namespace PoweredSoft.CQRS.FluentValidation
.AddFluentValidator<TCommand, TValidator>();
}
public static IServiceCollection AddQueryWithValidator<TQuery, TQueryResult, TQueryHandler, TValidator>(this IServiceCollection services)
public static IServiceCollection AddQuery<TQuery, TQueryResult, TQueryHandler, TValidator>(this IServiceCollection services)
where TQuery : class
where TQueryHandler : class, IQueryHandler<TQuery, TQueryResult>
where TValidator : class, IValidator<TQuery>

View File

@ -1,10 +0,0 @@
using System.Collections.Generic;
namespace PoweredSoft.CQRS.GraphQL.Abstractions
{
public interface IGraphQLFieldError
{
string Field { get; set; }
List<string> Errors { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System.Collections.Generic;
namespace PoweredSoft.CQRS.GraphQL.Abstractions
{
public interface IGraphQLValidationResult
{
bool IsValid { get; }
List<IGraphQLFieldError> Errors { get; }
}
}

View File

@ -1,13 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.GraphQL.Abstractions
{
public interface IGraphQLValidationService
{
Task<IGraphQLValidationResult> ValidateObjectAsync(object subject, CancellationToken cancellationToken = default);
Task<IGraphQLValidationResult> ValidateAsync<T>(T subject, CancellationToken cancellationToken = default);
}
}

View File

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
<Authors>PoweredSoft Team</Authors>
</PropertyGroup>
</Project>

View File

@ -1,21 +0,0 @@
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System;
namespace PoweredSoft.CQRS.GraphQL
{
public class GraphQLAdvanceQueryAggregate
{
public string Path { get; set; }
public AggregateType Type { get; set; }
internal IAggregate ToAggregate()
{
return new Aggregate
{
Path = Path,
Type = Type
};
}
}
}

View File

@ -1,51 +0,0 @@
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public class GraphQLAdvanceQueryFilter
{
public bool? And { get; set; }
public FilterType Type { get; set; }
public bool? CaseInsensitive { get; set; }
public string Path { get; set; }
public GraphQLVariantInput Value { get; set; }
public bool? Not { get; set; }
public List<GraphQLAdvanceQueryFilter> Filters { get; set; }
internal IFilter ToFilter()
{
if (Type == FilterType.Composite)
{
var ret = new CompositeFilter
{
And = And,
Type = FilterType.Composite
};
if (Filters == null)
ret.Filters = new List<IFilter>();
else
ret.Filters = Filters.Select(t => t.ToFilter()).ToList();
return ret;
}
else
{
return new SimpleFilter
{
And = And,
CaseInsensitive = CaseInsensitive,
Type = Type,
Not = Not,
Path = Path,
Value = Value.GetRawObjectValue()
};
}
}
}
}

View File

@ -1,21 +0,0 @@
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System;
namespace PoweredSoft.CQRS.GraphQL
{
public class GraphQLAdvanceQueryGroup
{
public string Path { get; set; }
public bool? Ascending { get; set; }
internal IGroup ToGroup()
{
return new Group
{
Path = Path,
Ascending = Ascending
};
}
}
}

View File

@ -1,11 +0,0 @@
using PoweredSoft.DynamicQuery.Core;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public class GraphQLAggregateResult
{
public string Path { get; set; }
public AggregateType Type { get; set; }
public GraphQLVariantResult Value { get; set; }
}
}

View File

@ -1,73 +0,0 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.CQRS.GraphQL.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System.Collections.Generic;
using System.Linq;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public class GraphQLDynamicQuery<TSource, TDestination> : GraphQLDynamicQuery, IDynamicQuery<TSource, TDestination>
where TSource : class
where TDestination : class
{
}
public class GraphQLDynamicQuery<TSource, TDestination, TParams> : GraphQLDynamicQuery<TSource, TDestination>,
IDynamicQuery<TSource, TDestination, TParams>
where TSource : class
where TDestination : class
where TParams : class
{
public TParams Params { get; set; }
public TParams GetParams() => Params;
}
public class GraphQLDynamicQuery : IDynamicQuery
{
public int? Page { get; set; }
public int? PageSize { get; set; }
public List<GraphQLSort> Sorts { get; set; }
public List<GraphQLAdvanceQueryFilter> Filters { get; set; }
public List<GraphQLAdvanceQueryGroup> Groups { get; set; }
public List<GraphQLAdvanceQueryAggregate> Aggregates { get; set; }
public List<IAggregate> GetAggregates()
{
if (Aggregates == null)
return new List<IAggregate>();
return Aggregates.Select(a => a.ToAggregate()).ToList();
}
public List<IFilter> GetFilters()
{
if (Filters == null)
return new List<IFilter>();
return Filters.Select(t => t.ToFilter()).ToList();
}
public List<IGroup> GetGroups()
{
if (Groups == null)
return new List<IGroup>();
return Groups.Select(t => t.ToGroup()).ToList();
}
public int? GetPage() => Page;
public int? GetPageSize() => PageSize;
public List<ISort> GetSorts()
{
if (Sorts == null)
return new List<ISort>();
return Sorts.Select(t => t.ToSort()).ToList();
}
}
}

View File

@ -1,59 +0,0 @@
using PoweredSoft.DynamicQuery.Core;
using System.Collections.Generic;
using System.Linq;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public class GraphQLDynamicQueryExecutionResult<TResult> : GraphQLDynamicQueryResult<TResult>
{
public List<GraphQLDynamicQueryGroupResult<TResult>> Groups { get; set; }
public long TotalRecords { get; set; }
public long? NumberOfPages { get; set; }
public void FromResult(IQueryExecutionResult<TResult> queryResult)
{
TotalRecords = queryResult.TotalRecords;
NumberOfPages = queryResult.NumberOfPages;
if (queryResult.Aggregates != null)
Aggregates = queryResult.Aggregates.Select(ConvertAggregateResult).ToList();
if (queryResult.Data != null)
Data = queryResult.Data;
if (queryResult is IQueryExecutionGroupResult<TResult> groupedResult)
Groups = groupedResult.Groups.Select(ConvertGroupResult).ToList();
}
protected virtual GraphQLDynamicQueryGroupResult<TResult> ConvertGroupResult(IGroupQueryResult<TResult> arg)
{
var group = new GraphQLDynamicQueryGroupResult<TResult>();
group.GroupPath = arg.GroupPath;
group.GroupValue = new GraphQLVariantResult(arg.GroupValue);
if (arg.Data != null)
group.Data = arg.Data;
if (arg.Aggregates != null)
group.Aggregates = arg.Aggregates.Select(ConvertAggregateResult).ToList();
if (arg.HasSubGroups)
group.SubGroups = arg.SubGroups.Select(ConvertGroupResult).ToList();
return group;
}
protected virtual GraphQLAggregateResult ConvertAggregateResult(IAggregateResult arg)
{
return new GraphQLAggregateResult
{
Path = arg.Path,
Type = arg.Type,
Value = new GraphQLVariantResult(arg.Value)
};
}
}
}

View File

@ -1,13 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public class GraphQLDynamicQueryGroupResult<TResult> : GraphQLDynamicQueryResult<TResult>
{
public string GroupPath { get; set; }
public GraphQLVariantResult GroupValue { get; set; }
public bool HasSubGroups => SubGroups?.Any() == true;
public List<GraphQLDynamicQueryGroupResult<TResult>> SubGroups { get; set; }
}
}

View File

@ -1,10 +0,0 @@
using System.Collections.Generic;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public class GraphQLDynamicQueryResult<TResult>
{
public List<TResult> Data { get; set; }
public List<GraphQLAggregateResult> Aggregates { get; set; }
}
}

View File

@ -1,17 +0,0 @@
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public class GraphQLSort
{
public string Path { get; set; }
public bool? Ascending { get; set; }
internal ISort ToSort()
{
return new Sort(Path, Ascending);
}
}
}

View File

@ -1,90 +0,0 @@
using System;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public abstract class GraphQLVariant
{
protected virtual string ResolveTypeName(object value)
{
if (value != null)
{
if (value is int)
return "int";
if (value is long)
return "long";
if (value is string)
return "string";
if (value is bool)
return "boolean";
if (value is decimal)
return "decimal";
if (value is DateTime)
return "datetime";
}
return null;
}
public string GetTypeName()
{
var value = GetRawObjectValue();
return ResolveTypeName(value);
}
public virtual void SetVariant(object raw)
{
ClearVariant();
if (raw != null)
{
if (raw is int rawInt)
IntValue = rawInt;
if (raw is long rawLong)
LongValue = rawLong;
if (raw is string rawStr)
StringValue = rawStr;
if (raw is bool rawBool)
BooleanValue = rawBool;
if (raw is decimal rawDec)
DecimalValue = rawDec;
if (raw is DateTime rawDt)
DateTimeValue = rawDt;
}
}
public virtual object GetRawObjectValue()
{
if (IntValue != null && IntValue is int)
return IntValue;
if (LongValue != null && LongValue is long)
return LongValue;
if (StringValue != null && StringValue is string)
return StringValue;
if (BooleanValue != null && BooleanValue is bool)
return BooleanValue;
if (DecimalValue != null && DecimalValue is decimal)
return DecimalValue;
if (DateTimeValue != null && DateTimeValue is DateTime)
return DateTimeValue;
return null;
}
public int? IntValue { get; set; }
public long? LongValue { get; set; }
public string StringValue { get; set; }
public decimal? DecimalValue { get; set; }
public DateTime? DateTimeValue { get; set; }
public bool? BooleanValue { get; set; }
public virtual void ClearVariant()
{
this.IntValue = null;
this.LongValue = null;
this.StringValue = null;
this.DecimalValue = null;
this.DateTimeValue = null;
this.BooleanValue = null;
}
}
}

View File

@ -1,8 +0,0 @@
using System;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public class GraphQLVariantInput : GraphQLVariant
{
}
}

View File

@ -1,60 +0,0 @@
using Newtonsoft.Json;
namespace PoweredSoft.CQRS.GraphQL.DynamicQuery
{
public class GraphQLVariantResult : GraphQLVariant
{
public GraphQLVariantResult()
{
}
public GraphQLVariantResult(object raw)
{
SetVariant(raw);
}
protected override string ResolveTypeName(object value)
{
var valueType = base.ResolveTypeName(value);
if (value != null && valueType == null)
return "json";
return valueType;
}
public override object GetRawObjectValue()
{
if (jsonValue != null)
return jsonValue;
return base.GetRawObjectValue();
}
private object jsonValue = null;
public string Json
{
get
{
if (jsonValue != null)
return JsonConvert.SerializeObject(jsonValue, new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
return null;
}
set
{
jsonValue = JsonConvert.DeserializeObject(value);
}
}
public override void ClearVariant()
{
base.ClearVariant();
this.jsonValue = null;
}
}
}

View File

@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
<Authors>PoweredSoft Team</Authors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="PoweredSoft.DynamicQuery" Version="3.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery.Abstractions\PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery\PoweredSoft.CQRS.DynamicQuery.csproj" />
</ItemGroup>
</Project>

View File

@ -1,11 +0,0 @@
using PoweredSoft.CQRS.GraphQL.Abstractions;
using System.Collections.Generic;
namespace PoweredSoft.CQRS.GraphQL.FluentValidation
{
public class GraphQLFieldError : IGraphQLFieldError
{
public string Field { get; set; }
public List<string> Errors { get; set; } = new List<string>();
}
}

View File

@ -1,28 +0,0 @@
using FluentValidation.Results;
using PoweredSoft.CQRS.GraphQL.Abstractions;
using System.Collections.Generic;
namespace PoweredSoft.CQRS.GraphQL.FluentValidation
{
public class GraphQLFluentValidationResult : IGraphQLValidationResult
{
public bool IsValid => Errors.Count == 0;
public List<IGraphQLFieldError> Errors { get; } = new List<IGraphQLFieldError>();
public static GraphQLFluentValidationResult From(ValidationResult result)
{
var model = new GraphQLFluentValidationResult();
foreach (var error in result.Errors)
{
var fieldError = new GraphQLFieldError
{
Field = error.PropertyName
};
fieldError.Errors.Add(error.ErrorMessage);
model.Errors.Add(fieldError);
}
return model;
}
}
}

View File

@ -1,47 +0,0 @@
using FluentValidation;
using PoweredSoft.CQRS.GraphQL.Abstractions;
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.GraphQL.FluentValidation
{
public class GraphQLFluentValidationService : IGraphQLValidationService
{
private readonly IServiceProvider serviceProvider;
public GraphQLFluentValidationService(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public async Task<IGraphQLValidationResult> ValidateAsync<T>(T subject, CancellationToken cancellationToken = default)
{
var validationService = serviceProvider.GetService(typeof(IValidator<T>)) as IValidator<T>;
if (validationService == null)
return new GraphQLValidResult();
var result = await validationService.ValidateAsync(subject, cancellationToken);
if (!result.IsValid)
return GraphQLFluentValidationResult.From(result);
return new GraphQLValidResult();
}
public async Task<IGraphQLValidationResult> ValidateObjectAsync(object subject, CancellationToken cancellationToken = default)
{
var validatorType = typeof(IValidator<>).MakeGenericType(subject.GetType());
var validationService = serviceProvider.GetService(validatorType) as IValidator;
if (validationService == null)
return new GraphQLValidResult();
var result = await validationService.ValidateAsync(new ValidationContext<object>(subject), cancellationToken);
if (!result.IsValid)
return GraphQLFluentValidationResult.From(result);
return new GraphQLValidResult();
}
}
}

View File

@ -1,11 +0,0 @@
using PoweredSoft.CQRS.GraphQL.Abstractions;
using System.Collections.Generic;
namespace PoweredSoft.CQRS.GraphQL.FluentValidation
{
public class GraphQLValidResult : IGraphQLValidationResult
{
public bool IsValid => true;
public List<IGraphQLFieldError> Errors { get; } = new List<IGraphQLFieldError>();
}
}

View File

@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
<Authors>PoweredSoft Team</Authors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="10.3.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PoweredSoft.CQRS.GraphQL.Abstractions\PoweredSoft.CQRS.GraphQL.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using PoweredSoft.CQRS.GraphQL.Abstractions;
namespace PoweredSoft.CQRS.GraphQL.FluentValidation
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddPoweredSoftGraphQLFluentValidation(this IServiceCollection services)
{
services.AddTransient<IGraphQLValidationService, GraphQLFluentValidationService>();
return services;
}
}
}

View File

@ -1,90 +0,0 @@
using HotChocolate.Types;
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.Abstractions.Discovery;
using PoweredSoft.CQRS.DynamicQuery.Discover;
using System;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate.DynamicQuery
{
internal class DynamicQueryObjectType : ObjectTypeExtension
{
private readonly IQueryDiscovery queryDiscovery;
public DynamicQueryObjectType(IQueryDiscovery queryDiscovery) : base()
{
this.queryDiscovery = queryDiscovery;
}
protected override void Configure(IObjectTypeDescriptor descriptor)
{
base.Configure(descriptor);
descriptor.Name("Query");
foreach(var q in queryDiscovery.GetQueries())
{
if (q.Category == "DynamicQuery" && q is DynamicQueryMeta dq)
{
var f = descriptor.Field(q.LowerCamelCaseName);
// service to execute with.
var queryHandlerServiceType = typeof(IQueryHandler<,>).MakeGenericType(dq.QueryType, dq.QueryResultType);
// destermine argument type.
Type argumentType;
Type runnerType;
if (dq.ParamsType != null)
{
argumentType = typeof(GraphQL.DynamicQuery.GraphQLDynamicQuery<,,>).MakeGenericType(
dq.SourceType, dq.DestinationType, dq.ParamsType);
runnerType = typeof(DynamicQueryRunnerWithParams<,,>)
.MakeGenericType(dq.SourceType, dq.DestinationType, dq.ParamsType);
}
else
{
argumentType = typeof(GraphQL.DynamicQuery.GraphQLDynamicQuery<,>).MakeGenericType(
dq.SourceType, dq.DestinationType);
runnerType = typeof(DynamicQueryRunner<,>)
.MakeGenericType(dq.SourceType, dq.DestinationType);
}
f.Argument("params", a => a
.Type(argumentType)
.DefaultValue(Activator.CreateInstance(argumentType))
);
// make generic type of outgoing type.
var resultType = typeof(GraphQL.DynamicQuery.GraphQLDynamicQueryExecutionResult<>)
.MakeGenericType(dq.DestinationType);
f.Type(resultType);
// security middleware
f.Use((sp, d) => new QueryAuthorizationMiddleware(q.QueryType, d));
// middleware to validate.
f.Use<QueryValidationMiddleware>();
// resolver
f.Resolve(async r =>
{
dynamic argument = r.ArgumentValue<object>("params");
// handler service.
var service = r.Service(queryHandlerServiceType);
// runner.
dynamic runner = Activator.CreateInstance(runnerType, new object[] { service });
// get outcome.
object outcome = await runner.RunAsync(argument, r.RequestAborted);
return outcome;
});
}
}
}
}
}

View File

@ -1,28 +0,0 @@
using PoweredSoft.CQRS.DynamicQuery;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.CQRS.GraphQL.DynamicQuery;
using System.Threading;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate.DynamicQuery
{
public class DynamicQueryRunner<TSource, TDestination>
where TSource : class
where TDestination : class
{
private readonly DynamicQueryHandler<TSource, TDestination> handler;
public DynamicQueryRunner(DynamicQueryHandler<TSource, TDestination> handler)
{
this.handler = handler;
}
public async Task<GraphQLDynamicQueryExecutionResult<TDestination>> RunAsync(IDynamicQuery<TSource, TDestination> query, CancellationToken cancellationToken = default)
{
var result = await handler.HandleAsync(query);
var outcome = new GraphQLDynamicQueryExecutionResult<TDestination>();
outcome.FromResult(result);
return outcome;
}
}
}

View File

@ -1,29 +0,0 @@
using PoweredSoft.CQRS.DynamicQuery;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.CQRS.GraphQL.DynamicQuery;
using System.Threading;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate.DynamicQuery
{
public class DynamicQueryRunnerWithParams<TSource, TDestination, TParams>
where TSource : class
where TDestination : class
where TParams : class
{
private readonly DynamicQueryHandler<TSource, TDestination, TParams> handler;
public DynamicQueryRunnerWithParams(DynamicQueryHandler<TSource, TDestination, TParams> handler)
{
this.handler = handler;
}
public async Task<GraphQLDynamicQueryExecutionResult<TDestination>> RunAsync(IDynamicQuery<TSource, TDestination, TParams> query, CancellationToken cancellationToken = default)
{
var result = await handler.HandleAsync(query);
var outcome = new GraphQLDynamicQueryExecutionResult<TDestination>();
outcome.FromResult(result);
return outcome;
}
}
}

View File

@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
<Authors>PoweredSoft Team</Authors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HotChocolate" Version="11.3.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PoweredSoft.CQRS.Abstractions\PoweredSoft.CQRS.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.GraphQL.DynamicQuery\PoweredSoft.CQRS.GraphQL.DynamicQuery.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.GraphQL.HotChocolate\PoweredSoft.CQRS.GraphQL.HotChocolate.csproj" />
</ItemGroup>
</Project>

View File

@ -1,15 +0,0 @@
using HotChocolate.Execution.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate.DynamicQuery
{
public static class RequestExecutorBuilderExtensions
{
public static IRequestExecutorBuilder AddPoweredSoftDynamicQueries(this IRequestExecutorBuilder builder)
{
builder.AddTypeExtension<DynamicQueryObjectType>();
return builder;
}
}
}

View File

@ -1,46 +0,0 @@
using HotChocolate;
using HotChocolate.Resolvers;
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.Abstractions.Security;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate
{
internal class MutationAuthorizationMiddleware
{
private readonly Type mutationType;
private readonly FieldDelegate _next;
public MutationAuthorizationMiddleware(Type mutationType,FieldDelegate next)
{
this.mutationType = mutationType;
_next = next;
}
public async Task InvokeAsync(IMiddlewareContext context)
{
var mutationAuthorizationService = context.Service<IServiceProvider>().GetService<ICommandAuthorizationService>();
if (mutationAuthorizationService != null)
{
var authorizationResult = await mutationAuthorizationService.IsAllowedAsync(mutationType);
if (authorizationResult != AuthorizationResult.Allowed)
{
var eb = ErrorBuilder.New()
.SetMessage(authorizationResult == AuthorizationResult.Unauthorized ? "Unauthorized" : "Forbidden")
.SetCode("AuthorizationResult")
.SetExtension("StatusCode", authorizationResult == AuthorizationResult.Unauthorized ? "401" : "403")
.SetPath(context.Path)
.AddLocation(context.Selection.SyntaxNode);
context.Result = eb.Build();
return;
}
}
await _next.Invoke(context);
}
}
}

View File

@ -1,79 +0,0 @@
using HotChocolate.Resolvers;
using HotChocolate.Types;
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.Abstractions.Discovery;
using System;
using System.Collections.Generic;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate
{
public class MutationObjectType : ObjectTypeExtension
{
private readonly ICommandDiscovery commandDiscovery;
public MutationObjectType(ICommandDiscovery commandDiscovery) : base()
{
this.commandDiscovery = commandDiscovery;
}
protected override void Configure(IObjectTypeDescriptor desc)
{
desc.Name("Mutation");
foreach (var m in commandDiscovery.GetCommands())
{
var mutationField = desc.Field(m.LowerCamelCaseName);
Type typeToGet;
if (m.CommandResultType == null)
typeToGet = typeof(ICommandHandler<>).MakeGenericType(m.CommandType);
else
typeToGet = typeof(ICommandHandler<,>).MakeGenericType(m.CommandType, m.CommandResultType);
if (m.CommandResultType == null)
mutationField.Type(typeof(int?));
else
mutationField.Type(m.CommandResultType);
//queryField.Use((sp, d) => new MutationAuthorizationMiddleware(m.CommandType, d));
if (m.CommandType.GetProperties().Length == 0)
{
mutationField.Resolve(async ctx =>
{
var queryArgument = Activator.CreateInstance(m.CommandType);
return await HandleMutation(m.CommandResultType != null, ctx, typeToGet, queryArgument);
});
continue;
}
mutationField.Argument("params", t => t.Type(m.CommandType));
mutationField.Resolve(async ctx =>
{
var queryArgument = ctx.ArgumentValue<object>("params");
return await HandleMutation(m.CommandResultType != null, ctx, typeToGet, queryArgument);
});
mutationField.Use<MutationParamRequiredMiddleware>();
mutationField.Use<MutationValidationMiddleware>();
}
}
private async System.Threading.Tasks.Task<object> HandleMutation(bool hasResult, IResolverContext ctx, Type typeToGet, object queryArgument)
{
dynamic service = ctx.Service(typeToGet);
if (hasResult)
{
var result = await service.HandleAsync((dynamic)queryArgument);
return result;
}
else
{
await service.HandleAsync((dynamic)queryArgument);
return null;
}
}
}
}

View File

@ -1,37 +0,0 @@
using HotChocolate;
using HotChocolate.Resolvers;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate
{
public class MutationParamRequiredMiddleware
{
private readonly FieldDelegate _next;
public MutationParamRequiredMiddleware(FieldDelegate next)
{
_next = next;
}
public async Task InvokeAsync(IMiddlewareContext context)
{
var queryArgument = context.ArgumentValue<object>("params");
if (queryArgument == null)
{
context.Result = ErrorBuilder.New()
.SetMessage("mutation argument is required")
.SetCode("400")
.SetPath(context.Path)
.AddLocation(context.Selection.SyntaxNode)
.Build();
return;
}
await _next.Invoke(context);
}
}
}

View File

@ -1,47 +0,0 @@
using HotChocolate;
using HotChocolate.Resolvers;
using PoweredSoft.CQRS.GraphQL.Abstractions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate
{
public class MutationValidationMiddleware
{
private readonly FieldDelegate _next;
public MutationValidationMiddleware(FieldDelegate next)
{
_next = next;
}
public async Task InvokeAsync(IMiddlewareContext context)
{
var queryArgument = context.ArgumentValue<object>("params");
if (queryArgument != null)
{
var service = context.Service<IGraphQLValidationService>();
var result = await service.ValidateObjectAsync(queryArgument, context.RequestAborted);
if (!result.IsValid)
{
var eb = ErrorBuilder.New()
.SetMessage("There are some validations errors")
.SetCode("ValidationError")
.SetPath(context.Path)
.AddLocation(context.Selection.SyntaxNode);
foreach (var error in result.Errors)
eb.SetExtension(error.Field, error.Errors);
context.Result = eb.Build();
return;
}
}
await _next.Invoke(context);
}
}
}

View File

@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
<Copyright>Powered Softwares Inc.</Copyright>
<PackageIconUrl>https://secure.gravatar.com/avatar/4e32f73820c16718909a06c2927f1f8b?s=512&amp;amp;r=g&amp;amp;d=retro</PackageIconUrl>
<Company>PoweredSoft</Company>
<Authors>PoweredSoft Team</Authors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HotChocolate" Version="11.3.4" />
<PackageReference Include="HotChocolate.Data" Version="11.3.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PoweredSoft.CQRS.Abstractions\PoweredSoft.CQRS.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.GraphQL.Abstractions\PoweredSoft.CQRS.GraphQL.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@ -1,46 +0,0 @@
using HotChocolate;
using HotChocolate.Resolvers;
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.Abstractions.Security;
using System;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate
{
public class QueryAuthorizationMiddleware
{
private readonly Type queryType;
private readonly FieldDelegate _next;
public QueryAuthorizationMiddleware(Type queryType, FieldDelegate next)
{
this.queryType = queryType;
_next = next;
}
public async Task InvokeAsync(IMiddlewareContext context)
{
var queryAuthorizationService = context.Service<IServiceProvider>().GetService<IQueryAuthorizationService>();
if (queryAuthorizationService != null)
{
var authorizationResult = await queryAuthorizationService.IsAllowedAsync(queryType);
if (authorizationResult != AuthorizationResult.Allowed)
{
var eb = ErrorBuilder.New()
.SetMessage(authorizationResult == AuthorizationResult.Unauthorized ? "Unauthorized" : "Forbidden")
.SetCode("AuthorizationResult")
.SetExtension("StatusCode", authorizationResult == AuthorizationResult.Unauthorized ? "401" : "403")
.SetPath(context.Path)
.AddLocation(context.Selection.SyntaxNode);
context.Result = eb.Build();
return;
}
}
await _next.Invoke(context);
}
}
}

View File

@ -1,89 +0,0 @@
using HotChocolate.Language;
using HotChocolate.Resolvers;
using HotChocolate.Types;
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.Abstractions.Discovery;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate
{
public class QueryObjectType : ObjectTypeExtension
{
private readonly IQueryDiscovery queryDiscovery;
public QueryObjectType(IQueryDiscovery queryDiscovery) : base()
{
this.queryDiscovery = queryDiscovery;
}
protected override void Configure(IObjectTypeDescriptor desc)
{
desc.Name("Query");
foreach (var q in queryDiscovery.GetQueries())
{
if (q.Category != "BasicQuery")
continue;
var queryField = desc.Field(q.LowerCamelCaseName);
var typeToGet = typeof(IQueryHandler<,>).MakeGenericType(q.QueryType, q.QueryResultType);
queryField.Use((sp, d) => new QueryAuthorizationMiddleware(q.QueryType, d));
// if its a IQueryable.
if (q.QueryResultType.Namespace == "System.Linq" && q.QueryResultType.Name.Contains("IQueryable"))
{
//waiting on answer to be determined.
//this does not work
//var genericArgument = q.QueryResultType.GetGenericArguments().First();
//var objectTypeOfAargument = typeof(ObjectType<>).MakeGenericType(genericArgument);
//var listType = typeof(ListType<>).MakeGenericType(objectTypeOfAargument);
//queryField.Type(objectTypeOfAargument);
//queryField.UseSingleOrDefault();
//queryField.UseProjection();
////queryField.UsePaging(listType);
queryField.Type(q.QueryResultType);
}
else
{
queryField.Type(q.QueryResultType);
}
if (q.QueryType.GetProperties().Length == 0)
{
queryField.Resolve(async ctx =>
{
var queryArgument = Activator.CreateInstance(q.QueryType);
return await HandleQuery(ctx, typeToGet, queryArgument);
});
continue;
}
queryField.Argument("params", t => t.Type(q.QueryType));
queryField.Resolve(async ctx =>
{
var queryArgument = ctx.ArgumentValue<object>("params");
return await HandleQuery(ctx, typeToGet, queryArgument);
});
/*
if (q.QueryObjectRequired)
queryField.Use<QueryParamRequiredMiddleware>();*/
queryField.Use<QueryValidationMiddleware>();
}
}
private async System.Threading.Tasks.Task<object> HandleQuery(IResolverContext resolverContext, Type typeToGet, object queryArgument)
{
dynamic service = resolverContext.Service(typeToGet);
var result = await service.HandleAsync((dynamic)queryArgument);
return result;
}
}
}

View File

@ -1,47 +0,0 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HotChocolate;
using HotChocolate.Resolvers;
using Newtonsoft.Json;
using PoweredSoft.CQRS.GraphQL.Abstractions;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate
{
public class QueryValidationMiddleware
{
private readonly FieldDelegate _next;
public QueryValidationMiddleware(FieldDelegate next)
{
_next = next;
}
public async Task InvokeAsync(IMiddlewareContext context)
{
var queryArgument = context.ArgumentValue<object>("params");
if (queryArgument != null)
{
var service = context.Service<IGraphQLValidationService>();
var result = await service.ValidateObjectAsync(queryArgument, context.RequestAborted);
if (!result.IsValid)
{
var eb = ErrorBuilder.New()
.SetMessage("There are some validations errors")
.SetCode("ValidationError")
.SetPath(context.Path)
.AddLocation(context.Selection.SyntaxNode);
foreach (var error in result.Errors)
eb.SetExtension(error.Field, error.Errors);
context.Result = eb.Build();
return;
}
}
await _next.Invoke(context);
}
}
}

View File

@ -1,22 +0,0 @@
using HotChocolate;
using HotChocolate.Execution.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace PoweredSoft.CQRS.GraphQL.HotChocolate
{
public static class RequestExecutorBuilderExtensions
{
public static IRequestExecutorBuilder AddPoweredSoftQueries(this IRequestExecutorBuilder builder)
{
builder.AddTypeExtension<QueryObjectType>();
return builder;
}
public static IRequestExecutorBuilder AddPoweredSoftMutations(this IRequestExecutorBuilder builder)
{
builder.AddTypeExtension<MutationObjectType>();
return builder;
}
}
}

Some files were not shown because too many files have changed in this diff Show More