-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #52 from engineering87/develop
refactor(core): extract common logic to base classes
- Loading branch information
Showing
8 changed files
with
255 additions
and
395 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// (c) 2024 Francesco Del Re <[email protected]> | ||
// This code is licensed under MIT license (see LICENSE.txt for details) | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.AspNetCore.SignalR; | ||
using Microsoft.Extensions.Logging; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using WART_Core.Entity; | ||
using WART_Core.Filters; | ||
|
||
namespace WART_Core.Controllers | ||
{ | ||
public abstract class WartBaseController<THub> : Controller where THub : Hub | ||
{ | ||
private readonly ILogger _logger; | ||
private readonly IHubContext<THub> _hubContext; | ||
private const string RouteDataKey = "REQUEST"; | ||
|
||
protected WartBaseController(IHubContext<THub> hubContext, ILogger logger) | ||
{ | ||
_hubContext = hubContext; | ||
_logger = logger; | ||
} | ||
|
||
/// <summary> | ||
/// Adds the request objects to RouteData. | ||
/// </summary> | ||
/// <param name="context">The action executing context.</param> | ||
public override void OnActionExecuting(ActionExecutingContext context) | ||
{ | ||
context?.RouteData.Values.Add(RouteDataKey, context.ActionArguments); | ||
base.OnActionExecuting(context); | ||
} | ||
|
||
/// <summary> | ||
/// Processes the executed action and sends the event to the SignalR hub if applicable. | ||
/// </summary> | ||
/// <param name="context">The action executed context.</param> | ||
public override async void OnActionExecuted(ActionExecutedContext context) | ||
{ | ||
if (context?.Result is ObjectResult objectResult) | ||
{ | ||
var exclusion = context.Filters.Any(f => f.GetType().Name == nameof(ExcludeWartAttribute)); | ||
if (!exclusion && context.RouteData.Values.TryGetValue(RouteDataKey, out var request)) | ||
{ | ||
var httpMethod = context.HttpContext?.Request.Method; | ||
var httpPath = context.HttpContext?.Request.Path; | ||
var remoteAddress = context.HttpContext?.Connection.RemoteIpAddress?.ToString(); | ||
var response = objectResult.Value; | ||
|
||
var wartEvent = new WartEvent(request, response, httpMethod, httpPath, remoteAddress); | ||
await SendToHub(wartEvent, [.. context.Filters]); | ||
} | ||
} | ||
|
||
base.OnActionExecuted(context); | ||
} | ||
|
||
/// <summary> | ||
/// Sends the current event to the SignalR hub. | ||
/// </summary> | ||
/// <param name="wartEvent">The current WartEvent.</param> | ||
/// <param name="filters">The list of filters applied to the request.</param> | ||
private async Task SendToHub(WartEvent wartEvent, List<IFilterMetadata> filters) | ||
{ | ||
try | ||
{ | ||
if (filters.Any(f => f.GetType().Name == nameof(GroupWartAttribute))) | ||
{ | ||
var wartGroup = filters.OfType<GroupWartAttribute>().FirstOrDefault(); | ||
var groups = wartGroup?.GroupNames; | ||
if (groups != null) | ||
{ | ||
foreach (var group in groups) | ||
{ | ||
await _hubContext.Clients.Group(group).SendAsync("Send", wartEvent.ToString()); | ||
_logger?.LogInformation($"Group: {group}, WartEvent: {wartEvent}"); | ||
} | ||
} | ||
} | ||
else | ||
{ | ||
await _hubContext.Clients.All.SendAsync("Send", wartEvent.ToString()); | ||
_logger?.LogInformation("Event: {EventName}, Details: {EventDetails}", nameof(WartEvent), wartEvent.ToString()); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger?.LogError(ex, "Error sending WartEvent to clients"); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,121 +1,19 @@ | ||
// (c) 2019 Francesco Del Re <[email protected]> | ||
// This code is licensed under MIT license (see LICENSE.txt for details) | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.AspNetCore.SignalR; | ||
using Microsoft.Extensions.Logging; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using WART_Core.Entity; | ||
using WART_Core.Filters; | ||
using WART_Core.Hubs; | ||
|
||
namespace WART_Core.Controllers | ||
{ | ||
/// <summary> | ||
/// The WART Controller | ||
/// </summary> | ||
public class WartController : Controller | ||
public class WartController : WartBaseController<WartHub> | ||
{ | ||
private readonly ILogger<WartController> _logger; | ||
private readonly IHubContext<WartHub> _hubContext; | ||
private const string RouteDataKey = "REQUEST"; | ||
|
||
public WartController(IHubContext<WartHub> hubContext, ILogger<WartController> logger) | ||
: base(hubContext, logger) | ||
{ | ||
_hubContext = hubContext; | ||
_logger = logger; | ||
} | ||
|
||
public WartController(IHubContext<WartHub> hubContext) | ||
{ | ||
_hubContext = hubContext; | ||
} | ||
|
||
/// <summary> | ||
/// WART OnActionExecuting override | ||
/// </summary> | ||
/// <param name="context">ActionExecutedContext context</param> | ||
public override void OnActionExecuting(ActionExecutingContext context) | ||
{ | ||
// add the request objects to RouteData | ||
context?.RouteData.Values.Add(RouteDataKey, context.ActionArguments); | ||
|
||
base.OnActionExecuting(context); | ||
} | ||
|
||
/// <summary> | ||
/// WART OnActionExecuted override | ||
/// </summary> | ||
/// <param name="context">ActionExecutedContext context</param> | ||
public override async void OnActionExecuted(ActionExecutedContext context) | ||
{ | ||
if (context?.Result is ObjectResult objectResult) | ||
{ | ||
// check for wart exclusion | ||
var exclusion = context.Filters.Any(f => f.GetType().Name == nameof(ExcludeWartAttribute)); | ||
if (!exclusion) | ||
{ | ||
// check for RouteData key existence | ||
if (context.RouteData.Values.TryGetValue(RouteDataKey, out var request)) | ||
{ | ||
// get the request objects from RouteData | ||
var httpMethod = context.HttpContext?.Request.Method; | ||
var httpPath = context.HttpContext?.Request.Path; | ||
var remoteAddress = context.HttpContext?.Connection.RemoteIpAddress?.ToString(); | ||
// get the object response | ||
var response = objectResult.Value; | ||
// create the new WartEvent and broadcast to all clients | ||
var wartEvent = new WartEvent(request, response, httpMethod, httpPath, remoteAddress); | ||
await SendToHub(wartEvent, [.. context.Filters]); | ||
} | ||
} | ||
} | ||
|
||
base.OnActionExecuted(context); | ||
} | ||
|
||
/// <summary> | ||
/// Send the current event to the SignalR hub. | ||
/// </summary> | ||
/// <param name="wartEvent">The current WartEvent</param> | ||
/// <param name="filters">The current Filters</param> | ||
/// <returns></returns> | ||
private async Task SendToHub(WartEvent wartEvent, List<IFilterMetadata> filters) | ||
{ | ||
try | ||
{ | ||
// check for specific groups | ||
if (filters.Any(f => f.GetType().Name == nameof(GroupWartAttribute))) | ||
{ | ||
// get the list of filters of type WartGroupAttribute | ||
var wartGroup = filters.FirstOrDefault(f => f.GetType() == typeof(GroupWartAttribute)) as GroupWartAttribute; | ||
var groups = wartGroup?.GroupNames; | ||
foreach (var group in groups) | ||
{ | ||
// send to the specific group | ||
await _hubContext?.Clients | ||
.Group(group) | ||
.SendAsync("Send", wartEvent.ToString()); | ||
|
||
_logger?.LogInformation($"Group: {group}, WartEvent: {wartEvent}"); | ||
} | ||
} | ||
else | ||
{ | ||
// send to all clients | ||
await _hubContext?.Clients.All | ||
.SendAsync("Send", wartEvent.ToString()); | ||
|
||
_logger?.LogInformation("Event: {EventName}, Details: {EventDetails}", nameof(WartEvent), wartEvent.ToString()); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger?.LogError(ex, "Error sending WartEvent to clients"); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,120 +1,19 @@ | ||
// (c) 2021 Francesco Del Re <[email protected]> | ||
// This code is licensed under MIT license (see LICENSE.txt for details) | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.AspNetCore.SignalR; | ||
using Microsoft.Extensions.Logging; | ||
using System.Threading.Tasks; | ||
using System; | ||
using WART_Core.Entity; | ||
using WART_Core.Hubs; | ||
using System.Linq; | ||
using WART_Core.Filters; | ||
using System.Collections.Generic; | ||
|
||
namespace WART_Core.Controllers | ||
{ | ||
/// <summary> | ||
/// The WART Controller | ||
/// The WART Controller with JWT authentication | ||
/// </summary> | ||
public class WartControllerJwt : Controller | ||
public class WartControllerJwt : WartBaseController<WartHubJwt> | ||
{ | ||
private readonly ILogger<WartControllerJwt> _logger; | ||
private readonly IHubContext<WartHubJwt> _hubContext; | ||
private const string RouteDataKey = "REQUEST"; | ||
|
||
public WartControllerJwt(IHubContext<WartHubJwt> hubContext, ILogger<WartControllerJwt> logger) | ||
: base(hubContext, logger) | ||
{ | ||
_hubContext = hubContext; | ||
_logger = logger; | ||
} | ||
|
||
public WartControllerJwt(IHubContext<WartHubJwt> hubContext) | ||
{ | ||
_hubContext = hubContext; | ||
} | ||
|
||
/// <summary> | ||
/// WART OnActionExecuting override | ||
/// </summary> | ||
/// <param name="context">ActionExecutedContext context</param> | ||
public override void OnActionExecuting(ActionExecutingContext context) | ||
{ | ||
// add the request objects to RouteData | ||
context?.RouteData.Values.Add(RouteDataKey, context.ActionArguments); | ||
|
||
base.OnActionExecuting(context); | ||
} | ||
|
||
/// <summary> | ||
/// WART OnActionExecuted override | ||
/// </summary> | ||
/// <param name="context">ActionExecutedContext context</param> | ||
public override async void OnActionExecuted(ActionExecutedContext context) | ||
{ | ||
if (context?.Result is ObjectResult objectResult) | ||
{ | ||
// check for wart exclusion | ||
var exclusion = context.Filters.Any(f => f.GetType().Name == nameof(ExcludeWartAttribute)); | ||
if (!exclusion) | ||
{ | ||
// check for RouteData key existence | ||
if (context.RouteData.Values.TryGetValue(RouteDataKey, out var request)) | ||
{ | ||
// get the request objects from RouteData | ||
var httpMethod = context.HttpContext?.Request.Method; | ||
var httpPath = context.HttpContext?.Request.Path; | ||
var remoteAddress = context.HttpContext?.Connection.RemoteIpAddress?.ToString(); | ||
// get the object response | ||
var response = objectResult.Value; | ||
// create the new WartEvent and broadcast to all clients | ||
var wartEvent = new WartEvent(request, response, httpMethod, httpPath, remoteAddress); | ||
await SendToHub(wartEvent, [.. context.Filters]); | ||
} | ||
} | ||
} | ||
|
||
base.OnActionExecuted(context); | ||
} | ||
|
||
/// <summary> | ||
/// Send the current event to the SignalR hub. | ||
/// </summary> | ||
/// <param name="wartEvent">The current WartEvent</param> | ||
/// <param name="filters">The current Filters</param> | ||
/// <returns></returns> | ||
private async Task SendToHub(WartEvent wartEvent, List<IFilterMetadata> filters) | ||
{ | ||
try | ||
{ | ||
// check for specific groups | ||
if (filters.Any(f => f.GetType().Name == nameof(GroupWartAttribute))) | ||
{ | ||
// get the list of filters of type WartGroupAttribute | ||
var wartGroup = filters.FirstOrDefault(f => f.GetType() == typeof(GroupWartAttribute)) as GroupWartAttribute; | ||
var groups = wartGroup?.GroupNames; | ||
foreach (var group in groups) | ||
{ | ||
await _hubContext?.Clients | ||
.Group(group) | ||
.SendAsync("Send", wartEvent.ToString()); | ||
|
||
_logger?.LogInformation($"Group: {group}, WartEvent: {wartEvent}"); | ||
} | ||
} | ||
else | ||
{ | ||
// send to all clients | ||
await _hubContext?.Clients.All | ||
.SendAsync("Send", wartEvent.ToString()); | ||
|
||
_logger?.LogInformation("Event: {EventName}, Details: {EventDetails}", nameof(WartEvent), wartEvent.ToString()); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger?.LogError(ex, "Error sending WartEvent to clients"); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
// (c) 2019 Francesco Del Re <[email protected]> | ||
// This code is licensed under MIT license (see LICENSE.txt for details) | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text.Json.Serialization; | ||
using WART_Core.Helpers; | ||
using WART_Core.Serialization; | ||
|
@@ -101,5 +102,25 @@ public T GetResponseObject<T>() where T : class | |
{ | ||
return SerializationHelper.Deserialize<T>(JsonResponsePayload); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Converts the WartEvent instance into a dictionary for flexible logging or data analysis. | ||
/// </summary> | ||
/// <returns>A dictionary representation of the event.</returns> | ||
public Dictionary<string, object> ToDictionary() | ||
{ | ||
return new Dictionary<string, object> | ||
{ | ||
{ "EventId", EventId }, | ||
{ "TimeStamp", TimeStamp }, | ||
{ "UtcTimeStamp", UtcTimeStamp }, | ||
{ "HttpMethod", HttpMethod }, | ||
{ "HttpPath", HttpPath }, | ||
{ "RemoteAddress", RemoteAddress }, | ||
{ "JsonRequestPayload", JsonRequestPayload }, | ||
{ "JsonResponsePayload", JsonResponsePayload }, | ||
{ "ExtraInfo", ExtraInfo } | ||
}; | ||
} | ||
} | ||
} |
Oops, something went wrong.