Medusa-CS/Medusa.Core/Services/HandlerService.cs

116 lines
4.5 KiB
C#

using Medusa.Core.Attributes;
using Medusa.Core.Handlers;
using System.Reflection;
using System.Xml.Linq;
namespace Medusa.Core.Services
{
public class HandlerService(IServiceProvider serviceProvider, ILogger<HandlerService> logger) : IHandlerService
{
private readonly IServiceProvider _serviceProvider = serviceProvider;
private readonly ILogger<HandlerService> _logger = logger;
public List<Type> Handlers { get; set; } = [];
public async Task<XDocument> Handle(string model, string module, string method, XDocument body)
{
foreach(var handler in Handlers)
{
//Module and service are on the attribute
var handlerAttribute = handler.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(HandlerAttribute));
if(handlerAttribute is null)
{
var response = await HandleInheritanceClass(handler, model, module, method, body);
if(response is not null)
{
return response;
}
continue;
}
var attributeModule = handlerAttribute.ConstructorArguments[0].Value.ToString();
var attributeMethod = handlerAttribute.ConstructorArguments[1].Value.ToString();
if(attributeModule == module && attributeMethod == method)
{
// Body param is optional so check for it
bool requiresXDocumentConstructor = handler.GetConstructors()
.Any(c => c.GetParameters().Any(p => p.ParameterType == typeof(XDocument)));
IHandler handlerInstance = requiresXDocumentConstructor
? (IHandler)ActivatorUtilities.CreateInstance(_serviceProvider, handler, body)
: (IHandler)ActivatorUtilities.CreateInstance(_serviceProvider, handler);
return await handlerInstance.HandleAsync(model);
}
}
//If no handler is found return an empty document
_logger.LogWarning($"No handler found for {model}/{module}/{method}");
return new XDocument();
}
private async Task<XDocument?> HandleInheritanceClass(Type handler, string model, string module, string method, XDocument body)
{
bool requiredXdocumentConstructor = handler.GetConstructors()
.Any(c => c.GetParameters().Any(p => p.ParameterType == typeof(XDocument)));
Handler handlerInstance = requiredXdocumentConstructor
? (Handler)ActivatorUtilities.CreateInstance(_serviceProvider, handler, body)
: (Handler)ActivatorUtilities.CreateInstance(_serviceProvider, handler);
try
{
var configureMethod = handler.GetMethod("Configure");
configureMethod?.Invoke(handlerInstance, null);
}
catch(NotImplementedException e)
{
_logger.LogError(e, "Configure method not implemented for {Handler}", handler.Name);
return null;
}
var handlerModule = handlerInstance.HandlerModule;
var handlerMethod = handlerInstance.HandlerMethod;
if(string.IsNullOrEmpty(handlerModule))
{
_logger.LogError("Module not set for {Handler}", handler.Name);
return null;
}
if(string.IsNullOrEmpty(handlerMethod))
{
_logger.LogError("Method not set for {Handler}", handler.Name);
return null;
}
if(handlerModule != module && handlerMethod != method)
return null;
var handleMethod = handlerInstance.GetType().GetMethod("Handle", [typeof(string)]);
var handleAsyncMethod = handlerInstance.GetType().GetMethod("HandleAsync", [typeof(string)]);
var response = new XDocument();
response = handleMethod?.DeclaringType != typeof(Handler)
? handlerInstance.Handle(model)
: handleAsyncMethod?.DeclaringType != typeof(Handler)
? await handlerInstance.HandleAsync(model)
: null;
if(response is null)
{
_logger.LogError("Handle and HandleAsync not implemented for {Handler}", handler.Name);
return null;
}
return response;
}
}
}