Skip to content
This repository was archived by the owner on Jan 24, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
154 changes: 154 additions & 0 deletions src/Griffin.Framework/Griffin.Cqs.AspNetCore/CqsMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using Griffin.Cqs.Authorization;
using Griffin.Cqs.Http;
using Griffin.Cqs.Net;
using Griffin.Net.Protocols.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Griffin.Cqs.AspNetCore
{
public class CqsMiddleware
{
public const string CqsPath = "/cqs";

private readonly RequestDelegate _next;
private readonly CqsMessageProcessor _messageProcessor;
private readonly CqsObjectMapper _cqsObjectMapper = new CqsObjectMapper();
private readonly ILogger<CqsMiddleware> _logger;

public CqsMiddleware(RequestDelegate next, CqsMessageProcessor messageProcessor, ILogger<CqsMiddleware> logger)
{
_next = next;
_messageProcessor = messageProcessor;
_logger = logger;

_logger.LogInformation("Griffin.Cqs.AspNetCore is running on path: {0}", CqsPath);
}

public async Task Invoke(HttpContext context)
{
if (context.Request.Path != CqsPath)
{
await _next(context);
return;
}

var name = context.Request.Headers["X-Cqs-Type"];
var dotNetType = context.Request.Headers["X-Cqs-Object-Type"];
var cqsName = context.Request.Headers["X-Cqs-Name"];

var json = "{}";
var reader = new StreamReader(context.Request.Body, Encoding.UTF8);
json = await reader.ReadToEndAsync();

if (string.IsNullOrWhiteSpace(json))
json = "{}";

object cqsObject;
if (!string.IsNullOrWhiteSpace(dotNetType))
{
cqsObject = _cqsObjectMapper.Deserialize(dotNetType, json);
if (cqsObject == null)
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.Features.Get<IHttpResponseFeature>().ReasonPhrase = "Unknown type: " + dotNetType;
_logger.LogWarning("Unknwon type: {0}", dotNetType);
return;
}
}
else if (!string.IsNullOrWhiteSpace(cqsName))
{
cqsObject = _cqsObjectMapper.Deserialize(cqsName, json);
if (cqsObject == null)
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.Features.Get<IHttpResponseFeature>().ReasonPhrase = "Unknown type: " + cqsName;
_logger.LogWarning("Unknwon type: {0}", cqsName);
return;
}
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
const string noCqsNameErrorMessage = "Expected a class name in the header 'X-Cqs-Name' or a .NET type name in the header 'X-Cqs-Object-Type'.";
context.Features.Get<IHttpResponseFeature>().ReasonPhrase = noCqsNameErrorMessage;
_logger.LogWarning(noCqsNameErrorMessage);
return;
}

ClientResponse cqsReplyObject = null;
Exception ex = null;
try
{
cqsReplyObject = await _messageProcessor.ProcessAsync(cqsObject);
}
catch (AggregateException e1)
{
ex = e1.InnerException;
}

if (ex is HttpException)
{
_logger.LogWarning("Failed to process {0}, Exception: \r\n{1}", json, ex);
// TODO: log to OneTrueError or something
context.Response.StatusCode = ((HttpException)ex).HttpCode;
context.Features.Get<IHttpResponseFeature>().ReasonPhrase = FirstLine(ex.Message);
return;
}
if (ex is AuthorizationException)
{
_logger.LogWarning("Failed to process {0}, Exception: \r\n{1}", json, ex);
// TODO: log to OneTrueError or something
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Features.Get<IHttpResponseFeature>().ReasonPhrase = FirstLine(ex.Message);
return;
}
if (ex != null)
{
_logger.LogError("Failed to process {0}, Exception: \r\n{1}", json, ex.Message);
// TODO: log to OneTrueError or something
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Features.Get<IHttpResponseFeature>().ReasonPhrase = FirstLine(ex.Message);
return;
}

context.Response.ContentType = "application/json;encoding=utf8";

if (cqsReplyObject.Body != null)
{
context.Response.Headers["X-Cqs-Object-Type"] = cqsReplyObject.Body.GetType().GetSimpleAssemblyQualifiedName();
context.Response.Headers["X-Cqs-Name"] = cqsReplyObject.Body.GetType().Name;
if (cqsReplyObject.Body is Exception)
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

var contentType = "application/json;encoding=utf8";
json = _cqsObjectMapper.Deserializer != null ? _cqsObjectMapper.Deserializer.Serialize(cqsReplyObject.Body, out contentType) : JsonConvert.SerializeObject(cqsReplyObject.Body);

var buffer = Encoding.UTF8.GetBytes(json);
await context.Response.Body.WriteAsync(buffer, 0, buffer.Length);
}
else
context.Response.StatusCode = (int)HttpStatusCode.NoContent;
}


private string FirstLine(string msg)
{
var pos = msg.IndexOfAny(new[] { '\r', '\n' });
if (pos == -1)
return msg;

return msg.Substring(0, pos);
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{13454511-A7C6-413E-AAC9-3E3464D3D1A7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Griffin.Cqs.AspNetCore</RootNamespace>
<AssemblyName>Griffin.Cqs.AspNetCore</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Griffin.Cqs.AspNetCore.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\Griffin.Cqs.AspNetCore.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Http.Abstractions, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Abstractions.1.1.2\lib\net451\Microsoft.AspNetCore.Http.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Features, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Features.1.1.2\lib\net451\Microsoft.AspNetCore.Http.Features.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.1.1.1\lib\netstandard1.1\Microsoft.Extensions.DependencyInjection.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.1.1.1\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.1.1.2\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Primitives, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Primitives.1.1.1\lib\netstandard1.0\Microsoft.Extensions.Primitives.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.3.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.4.3.1\lib\netstandard1.0\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CqsMiddleware.cs" />
<Compile Include="GriffinCqsApplicationBuilderExtensions.cs" />
<Compile Include="GriffinCqsServiceCollectionExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Griffin.Core.Microsoft.Extensions.DependencyInjection\Griffin.Core.Microsoft.Extensions.DependencyInjection.csproj">
<Project>{0f3ecdb7-c463-4fb9-bdec-1d53b01676fc}</Project>
<Name>Griffin.Core.Microsoft.Extensions.DependencyInjection</Name>
</ProjectReference>
<ProjectReference Include="..\Griffin.Core\Griffin.Core.csproj">
<Project>{744709d5-d4d5-4551-9ebd-cbd7bdf58f5f}</Project>
<Name>Griffin.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Griffin.Cqs\Griffin.Cqs.csproj">
<Project>{9febad0a-cc01-4105-ac0c-c382e64164e6}</Project>
<Name>Griffin.Cqs</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Griffin.Cqs.AspNetCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.AspNetCore.Builder
{
public static class GriffinCqsApplicationBuilderExtensions
{
/// <summary>
/// Adds GriffinCqs to the pipeline.
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
public static IApplicationBuilder UseGriffinCqs(this IApplicationBuilder app)
{
app.UseMiddleware<CqsMiddleware>();
return app;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Griffin.Core.Microsoft.Extensions.DependencyInjection;
using Griffin.Cqs.InversionOfControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.Extensions.DependencyInjection
{
public static class GriffinCqsServiceCollectionExtensions
{
/// <summary>
/// Adds the Griffin.Cqs.AspNetCore services to the IServiceCollection.
/// You do not have to use the scanAssemblies parameter but then you have to register the Handlers yourself.
/// </summary>
/// <param name="services"></param>
/// <param name="scanAssemblies">will be scanned for <see cref="Griffin.Container.ContainerServiceAttribute"/> and registers all these classes as service</param>
public static void AddGriffinCqs(this IServiceCollection services, params Assembly[] scanAssemblies)
{
services.AddSingleton(s =>
{
var builder = new IocBusBuilder(new MicrosoftDependencyInjectionAdapter(s));
return builder.BuildMessageProcessor();
});
services.RegisterServices(scanAssemblies);
}
}
}
Loading