Introduce async extensions for RouteFilters (#16)

Rework filter logic to reuse filter objects on the scope of a request
This commit is contained in:
2022-05-04 08:22:32 +02:00
committed by GitHub
parent 035fecc1e3
commit 1b438c8bd4
8 changed files with 112 additions and 26 deletions
+5 -5
View File
@@ -44,9 +44,9 @@ jobs:
- name: Build MTSC project
run: dotnet build MTSC -c $env:Configuration
- name: Push nuget package
uses: brandedoutcast/publish-nuget@v2.5.5
with:
PROJECT_FILE_PATH: MTSC\MTSC.csproj
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
- name: Package
run: dotnet pack -c Release -o . $env:Source_Project_Path
- name: Publish
run: dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
+2
View File
@@ -98,6 +98,8 @@ namespace MTSC.UnitTests
Assert.IsTrue(NonActioningFilterAttribute.RequestCalled);
Assert.IsTrue(NonActioningFilterAttribute.ResponseCalled);
Assert.IsTrue(NonActioningFilterAttribute.RequestAsyncCalled);
Assert.IsTrue(NonActioningFilterAttribute.ResponseAsyncCalled);
}
[TestMethod]
@@ -1,5 +1,6 @@
using MTSC.Common.Http;
using MTSC.Common.Http.Attributes;
using System.Threading.Tasks;
namespace MTSC.UnitTests.RoutingModules
{
@@ -7,6 +8,8 @@ namespace MTSC.UnitTests.RoutingModules
{
public static bool RequestCalled { get; private set; }
public static bool ResponseCalled { get; private set; }
public static bool RequestAsyncCalled { get; private set; }
public static bool ResponseAsyncCalled { get; private set; }
public override RouteEnablerResponse HandleRequest(RouteContext routeContext)
{
@@ -19,5 +22,17 @@ namespace MTSC.UnitTests.RoutingModules
ResponseCalled = true;
base.HandleResponse(routeContext);
}
public override Task<RouteEnablerAsyncResponse> HandleRequestAsync(RouteContext routeContext)
{
RequestAsyncCalled = true;
return base.HandleRequestAsync(routeContext);
}
public override Task HandleResponseAsync(RouteContext routeContext)
{
ResponseAsyncCalled = true;
return base.HandleResponseAsync(routeContext);
}
}
}
@@ -1,16 +1,21 @@
using System;
using System.Threading.Tasks;
namespace MTSC.Common.Http.Attributes
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public abstract class RouteFilterAttribute : Attribute
{
public virtual RouteEnablerResponse HandleRequest(RouteContext routeFilterContext) => RouteEnablerResponse.Accept;
public virtual RouteEnablerResponse HandleRequest(RouteContext routeContext) => RouteEnablerResponse.Accept;
public virtual void HandleResponse(RouteContext routeFilterContext)
public virtual Task<RouteEnablerAsyncResponse> HandleRequestAsync(RouteContext routeContext) => Task.FromResult<RouteEnablerAsyncResponse>(RouteEnablerAsyncResponse.Accept);
public virtual void HandleResponse(RouteContext routeContext)
{
}
public virtual Task HandleResponseAsync(RouteContext routeContext) => Task.CompletedTask;
public virtual RouteFilterExceptionHandlingResponse HandleException(RouteContext routeFilterContext, Exception exception)
{
return RouteFilterExceptionHandlingResponse.NotHandled;
+3 -1
View File
@@ -1,4 +1,5 @@
using MTSC.ServerSide;
using MTSC.Common.Http.Attributes;
using MTSC.ServerSide;
using Slim;
using System.Collections.Generic;
using System.Threading;
@@ -12,6 +13,7 @@ namespace MTSC.Common.Http
public ClientData Client { get; }
public Dictionary<string, string> UrlValues { get; }
public IServiceProvider ScopedServiceProvider { get; }
public List<RouteFilterAttribute> RouteFilters { get; } = new List<RouteFilterAttribute>();
public HttpResponse HttpResponse { get; set; }
public CancellationToken CancelRequest => this.Client.CancellationToken;
public Dictionary<string, object> Resources { get; set; } = new();
@@ -0,0 +1,27 @@
namespace MTSC.Common.Http
{
public abstract class RouteEnablerAsyncResponse
{
public static RouteEnablerAsyncResponseAccept Accept { get; } = new RouteEnablerAsyncResponseAccept();
public static RouteEnablerAsyncResponseError Error(HttpResponse responseMessage)
{
return new RouteEnablerAsyncResponseError(responseMessage);
}
public sealed class RouteEnablerAsyncResponseAccept : RouteEnablerAsyncResponse
{
internal RouteEnablerAsyncResponseAccept()
{
}
}
public sealed class RouteEnablerAsyncResponseError : RouteEnablerAsyncResponse
{
public HttpResponse Response { get; }
internal RouteEnablerAsyncResponseError(HttpResponse responseMessage)
{
this.Response = responseMessage;
}
}
}
}
+3 -3
View File
@@ -5,13 +5,13 @@
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<ApplicationIcon />
<StartupObject />
<Version>5.3.0</Version>
<Version>5.4.0</Version>
<LangVersion>latest</LangVersion>
<Authors>Alexandru-Victor Macocian</Authors>
<Product>MTSC</Product>
<Description>Modular TCP Server and Client</Description>
<AssemblyVersion>5.3.0.0</AssemblyVersion>
<FileVersion>5.3.0.0</FileVersion>
<AssemblyVersion>5.4.0.0</AssemblyVersion>
<FileVersion>5.4.0.0</FileVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Platforms>AnyCPU;x64</Platforms>
<PackageProjectUrl>https://github.com/AlexMacocian/MTSC</PackageProjectUrl>
+50 -15
View File
@@ -235,9 +235,9 @@ namespace MTSC.ServerSide.Handlers
client,
module.ScopedServiceProvider,
urlValues.ToDictionary(u => u.Placeholder, u => u.Value));
foreach(var filterType in filterTypes)
routeContext.RouteFilters.AddRange(filterTypes.Select(filterType => module.ScopedServiceProvider.GetService(filterType) as RouteFilterAttribute));
foreach(var filter in routeContext.RouteFilters)
{
var filter = module.ScopedServiceProvider.GetService(filterType) as RouteFilterAttribute;
var filterResponse = filter.HandleRequest(routeContext);
if (filterResponse is RouteEnablerResponse.RouteEnablerResponseAccept)
{
@@ -258,11 +258,23 @@ namespace MTSC.ServerSide.Handlers
}
}
this.RouteHandleRequest(module, routeContext, filterTypes).ContinueWith(task =>
{
this.QueueResponse(client, task.Result);
});
this.FiltersHandleRequestAsync(routeContext)
.ContinueWith(task =>
{
var routeEnablerAsyncResponse = task.Result;
if (routeEnablerAsyncResponse is RouteEnablerAsyncResponse.RouteEnablerAsyncResponseError)
{
return;
}
this.RouteHandleRequest(module, routeContext, filterTypes)
.ContinueWith(async task =>
{
await FiltersHandleResponseAsync(routeContext);
this.QueueResponse(client, task.Result);
return Task.CompletedTask;
});
});
return true;
}
@@ -369,6 +381,37 @@ namespace MTSC.ServerSide.Handlers
}
}
private async Task<RouteEnablerAsyncResponse> FiltersHandleRequestAsync(RouteContext routeContext)
{
foreach (var filter in routeContext.RouteFilters)
{
var filterResponse = await filter.HandleRequestAsync(routeContext);
if (filterResponse is RouteEnablerAsyncResponse.RouteEnablerAsyncResponseAccept)
{
continue;
}
else if (filterResponse is RouteEnablerAsyncResponse.RouteEnablerAsyncResponseError errorResponse)
{
this.QueueResponse(routeContext.Client, errorResponse.Response);
return errorResponse;
}
else
{
throw new InvalidOperationException($"RouteEnablerAsyncResponse should be one of the types {typeof(RouteEnablerAsyncResponse.RouteEnablerAsyncResponseAccept)} or {typeof(RouteEnablerAsyncResponse.RouteEnablerAsyncResponseError)}!");
}
}
return RouteEnablerAsyncResponse.Accept;
}
private async Task FiltersHandleResponseAsync(RouteContext routeContext)
{
foreach(var filter in routeContext.RouteFilters)
{
await filter.HandleResponseAsync(routeContext);
}
}
private async Task<HttpResponse> RouteHandleRequest(
HttpRouteBase httpRouteBase,
RouteContext routeContext,
@@ -419,7 +462,6 @@ namespace MTSC.ServerSide.Handlers
return module;
}
private void RegisterRoute(HttpMethods method, string uri, Type routeType)
{
if (!typeof(HttpRouteBase).IsAssignableFrom(routeType))
@@ -429,7 +471,6 @@ namespace MTSC.ServerSide.Handlers
this.moduleDictionary[method].Add((new ExtendedUrl(uri), routeType, new List<Type>()));
}
private void PrepareRoutePropertyCache(Type routeType)
{
if (this.routePropertyCache.ContainsKey(routeType))
@@ -452,7 +493,6 @@ namespace MTSC.ServerSide.Handlers
this.routePropertyCache[routeType] = propertyAndAttributesList;
}
private bool TryMatchUrl(HttpMethods method, string uri, out List<UrlValue> urlValues, out Type type, out List<Type> filters)
{
urlValues = null;
@@ -472,7 +512,6 @@ namespace MTSC.ServerSide.Handlers
return false;
}
private void SetModuleProperties(HttpRouteBase module, RouteContext routeContext)
{
foreach ((var attribute, var propertyInfo) in this.routePropertyCache[module.GetType()])
@@ -495,8 +534,6 @@ namespace MTSC.ServerSide.Handlers
}
}
private static void SetPropertyValue(PropertyInfo propertyInfo, object value, HttpRouteBase module)
{
if (propertyInfo.CanWrite is false)
@@ -510,8 +547,6 @@ namespace MTSC.ServerSide.Handlers
}
}
private static HttpResponse NotFound404 => new()
{
StatusCode = StatusCodes.NotFound