mirror of
https://github.com/AlexMacocian/MTSC.git
synced 2026-07-21 01:39:31 +00:00
Introduce async extensions for RouteFilters (#16)
Rework filter logic to reuse filter objects on the scope of a request
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user