Skip to content

Commit

Permalink
Merge branch 'master' into ft-grpc
Browse files Browse the repository at this point in the history
  • Loading branch information
cime authored Apr 20, 2021
2 parents 0b7bccd + ee5363d commit 69594f8
Show file tree
Hide file tree
Showing 34 changed files with 936 additions and 142 deletions.
17 changes: 16 additions & 1 deletion .github/workflows/dotnetcore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,27 @@ jobs:

runs-on: ubuntu-latest

services:
postgres:
image: postgres:12
env:
POSTGRES_USER: coresharp
POSTGRES_PASSWORD: coresharp
POSTGRES_DB: coresharp
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v1
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.100
dotnet-version: '5.0.x'
- name: Test with dotnet
run: dotnet test
- name: Build with dotnet
Expand Down
8 changes: 5 additions & 3 deletions CoreSharp.Breeze.Tests/BaseDatabaseTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ protected virtual Configuration CreateNHibernateConfiguration(Container containe
var persistenceModel = GetPersistenceModel(container, config);
return Fluently.Configure(config)
.Database(
MsSqlConfiguration.MsSql2012.ConnectionString(o => o
PostgreSQLConfiguration.PostgreSQL82.ConnectionString(o => o
.Database("coresharp")
.Server("(local)")
.TrustedConnection())
.Host("localhost")
.Username("coresharp")
.Password("coresharp")
.Port(5432))
)
//.AppendEventListeners<User>(container)
.SetDefaultProperties()
Expand Down
2 changes: 1 addition & 1 deletion CoreSharp.Breeze.Tests/BreezeDatabaseTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ protected virtual void FillDatabase(ISession session)
{
CompositeOrder = compositeOrder,
Product = products[(i + j) % 10],
Price = i * j,
Price = (int)(i * j),
Quantity = i + j
});
}
Expand Down
4 changes: 3 additions & 1 deletion CoreSharp.Breeze.Tests/CoreSharp.Breeze.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>latest</LangVersion>
<IsPackable>false</IsPackable>
</PropertyGroup>
Expand All @@ -20,6 +20,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.0.1" />
<PackageReference Include="Npgsql" Version="5.0.4" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
76 changes: 76 additions & 0 deletions CoreSharp.Common.Abstractions/Attributes/HttpMethodAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;

namespace CoreSharp.Common.Attributes
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class HttpMethodAttribute : Attribute
{
public IEnumerable<string> HttpMethods { get; }

public HttpMethodAttribute(IEnumerable<string> httpMethods)
{
HttpMethods = httpMethods;
}
}

public class HttpGetAttribute : HttpMethodAttribute
{
private static readonly IEnumerable<string> SupportedMethods = new [] { "GET" };

public HttpGetAttribute()
: base(SupportedMethods)
{
}
}

public class HttpPostAttribute : HttpMethodAttribute
{
private static readonly IEnumerable<string> SupportedMethods = new [] { "POST" };

public HttpPostAttribute()
: base(SupportedMethods)
{
}
}

public class HttpPutAttribute : HttpMethodAttribute
{
private static readonly IEnumerable<string> SupportedMethods = new [] { "PUT" };

public HttpPutAttribute()
: base(SupportedMethods)
{
}
}

public class HttpDeleteAttribute : HttpMethodAttribute
{
private static readonly IEnumerable<string> SupportedMethods = new [] { "DELETE" };

public HttpDeleteAttribute()
: base(SupportedMethods)
{
}
}

public class HttpPatchAttribute : HttpMethodAttribute
{
private static readonly IEnumerable<string> SupportedMethods = new [] { "PATCH" };

public HttpPatchAttribute()
: base(SupportedMethods)
{
}
}

public class HttpHeadAttribute : HttpMethodAttribute
{
private static readonly IEnumerable<string> SupportedMethods = new [] { "HEAD" };

public HttpHeadAttribute()
: base(SupportedMethods)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>8</LangVersion>
<RootNamespace>CoreSharp.Common</RootNamespace>
</PropertyGroup>

</Project>
6 changes: 4 additions & 2 deletions CoreSharp.Common.Tests/BaseTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using SimpleInjector;
using CoreSharp.Cqrs.Events;
using SimpleInjector;
using SimpleInjector.Lifestyles;
using Xunit;

Expand Down Expand Up @@ -30,7 +31,7 @@ protected virtual void ConfigureContainer(Container container)

protected virtual void SetUp()
{

}

protected virtual void Cleanup()
Expand All @@ -39,6 +40,7 @@ protected virtual void Cleanup()

private void Configure(Container container)
{
var ep = new EventAggregator(container); // TODO: remove
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
ConfigureContainer(container);
container.RegisterPackages();
Expand Down
3 changes: 2 additions & 1 deletion CoreSharp.Common.Tests/CoreSharp.Common.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

Expand All @@ -17,6 +17,7 @@

<ItemGroup>
<ProjectReference Include="..\CoreSharp.Common\CoreSharp.Common.csproj" />
<ProjectReference Include="..\CoreSharp.Cqrs\CoreSharp.Cqrs.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,53 +11,38 @@
using CoreSharp.Cqrs.AspNetCore.Options;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using NHibernate;

namespace CoreSharp.Cqrs.AspNetCore
{
// ReSharper disable once ClassNeverInstantiated.Global
public class CqrsMiddleware : IMiddleware
public class CommandHandlerMiddleware : IMiddleware
{
public static readonly string ContextKey = "CQRS";

private readonly CqrsFormatterRegistry _registry;
private readonly ICqrsOptions _options;

private readonly Lazy<Dictionary<string, CommandInfo>> _commandTypes;
private readonly Lazy<Dictionary<string, QueryInfo>> _queryTypes;

private readonly ConcurrentDictionary<Type, dynamic> _deserializeMethods = new ConcurrentDictionary<Type, dynamic>();
private static readonly MethodInfo CreateDeserializeLambdaMethodInfo = typeof(CqrsMiddleware).GetMethod(nameof(CreateDeserializeLambda), BindingFlags.NonPublic | BindingFlags.Static);
private static readonly MethodInfo CreateDeserializeLambdaMethodInfo = typeof(CommandHandlerMiddleware).GetMethod(nameof(CreateDeserializeLambda), BindingFlags.NonPublic | BindingFlags.Static);

public CqrsMiddleware(CqrsFormatterRegistry registry, ICqrsOptions options)
public CommandHandlerMiddleware(CqrsFormatterRegistry registry, ICqrsOptions options)
{
_registry = registry;
_options = options;

_commandTypes = new Lazy<Dictionary<string, CommandInfo>>(() => options.GetCommandTypes().ToDictionary(
keySelector: options.GetCommandKey,
elementSelector: type => type,
comparer: StringComparer.OrdinalIgnoreCase));

_queryTypes = new Lazy<Dictionary<string, QueryInfo>>(() => options.GetQueryTypes().ToDictionary(
keySelector: options.GetQueryKey,
elementSelector: info => info,
comparer: StringComparer.OrdinalIgnoreCase));
_commandTypes = new Lazy<Dictionary<string, CommandInfo>>(() =>
options.GetCommandTypes()
.SelectMany(x => x.HttpMethods, (ci, method) => new { CommandInfo = ci, HttpMethod = method})
.ToDictionary(
keySelector: (x) => $"{x.HttpMethod} {options.GetCommandPath(x.CommandInfo)}",
elementSelector: x => x.CommandInfo,
comparer: StringComparer.OrdinalIgnoreCase));
}

public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (context.Request.Method == HttpMethod.Post.Method && context.Request.Path.Value.StartsWith(_options.CommandsPath, StringComparison.OrdinalIgnoreCase))
{
await HandleCommand(context, _options);
}
else if (context.Request.Path.Value.StartsWith(_options.QueriesPath, StringComparison.OrdinalIgnoreCase))
{
await HandleQuery(context, _options);
}
else
{
await next(context);
}
await HandleCommand(context, _options);
}

private static Func<ICqrsFormatter, HttpRequest, ValueTask<T>> CreateDeserializeLambda<T>()
Expand All @@ -74,16 +59,17 @@ private static Func<ICqrsFormatter, HttpRequest, ValueTask<T>> CreateDeserialize

private async Task HandleCommand(HttpContext context, ICqrsOptions options)
{
var path = options.GetCommandPath(context.Request.Path.Value);
var path = context.Request.Path;
var method = context.Request.Method;

if (!_commandTypes.Value.ContainsKey(path))
if (!_commandTypes.Value.ContainsKey($"{method} {path}"))
{
throw new CommandNotFoundException($"Command '{path}' not found");
throw new CommandNotFoundException($"Command '{method} {path}' not found");
}

dynamic result = null;

var info = _commandTypes.Value[path];
var info = _commandTypes.Value[$"{method} {path}"];
var exposeAttribute = info.CommandType.GetCustomAttribute<ExposeAttribute>();
var formatter = _registry.GetFormatter(exposeAttribute.Formatter);

Expand All @@ -93,10 +79,10 @@ private async Task HandleCommand(HttpContext context, ICqrsOptions options)
return mi.Invoke(null, null);
});

dynamic command = await deserializeMethod(formatter, context.Request);
var command = await deserializeMethod(formatter, context.Request);

dynamic handler = options.GetInstance(info.CommandHandlerType);
context.Items[ContextKey] = new CqrsContext(context.Request.Path.Value, path, CqrsType.Command, info.CommandHandlerType);
context.Items[IOwinContextExtensions.ContextKey] = new CqrsContext(context.Request.Path.Value, path, CqrsType.Command, info.CommandHandlerType);

if (info.IsGeneric)
{
Expand Down Expand Up @@ -143,62 +129,6 @@ private async Task HandleCommand(HttpContext context, ICqrsOptions options)
}
}

private async Task HandleQuery(HttpContext context, ICqrsOptions options)
{
var path = options.GetQueryPath(context.Request.Path.Value);

if (!_queryTypes.Value.ContainsKey(path))
{
throw new QueryNotFoundException($"Query '{path}' not found");
}

var info = _queryTypes.Value[path];
var exposeAttribute = info.QueryType.GetCustomAttribute<ExposeAttribute>();
var formatter = _registry.GetFormatter(exposeAttribute.Formatter);

var deserializeMethod = _deserializeMethods.GetOrAdd(info.QueryType, (t) =>
{
var mi = CreateDeserializeLambdaMethodInfo.MakeGenericMethod(t);
return mi.Invoke(null, null);
});

dynamic query = await deserializeMethod(formatter, context.Request);

dynamic handler = options.GetInstance(info.QueryHandlerType);

context.Items[ContextKey] = new CqrsContext(context.Request.Path.Value, path, CqrsType.Command, info.QueryHandlerType);

dynamic result;

if (info.IsAsync)
{
result = await handler.HandleAsync(query, context.RequestAborted);
}
else
{
result = handler.Handle(query);
}

string json = null;

if (result != null)
{
json = result is string ? result : await formatter.SerializeAsync(result, context.Request);
}

context.Response.ContentType = formatter.ContentType;

if (json != null)
{
context.Response.StatusCode = (int)HttpStatusCode.OK;
await HttpResponseWritingExtensions.WriteAsync(context.Response, json, context.RequestAborted);
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.NoContent;
}
}

private void CloseSession()
{
var session = (global::NHibernate.ISession) _options.GetInstance(typeof(global::NHibernate.ISession));
Expand All @@ -210,7 +140,7 @@ private void CloseSession()

if (session.GetSessionImplementation().TransactionInProgress)
{
var tx = session.Transaction;
var tx = session.GetCurrentTransaction();
try
{
if (tx.IsActive) tx.Commit();
Expand All @@ -229,11 +159,11 @@ private void CloseSession()
}
}

public static class CqrsMiddlewareExtensions
public static class CommandHandlerMiddlewareExtensions
{
public static IApplicationBuilder UseCqrs(this IApplicationBuilder builder)
public static IApplicationBuilder UseCommands(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CqrsMiddleware>();
return builder.UseMiddleware<CommandHandlerMiddleware>();
}
}
}
Loading

0 comments on commit 69594f8

Please sign in to comment.