public ServiceDiscovery(IServiceProvider serviceProvider, ILogger <ServiceDiscovery> logger, CqApiOptions options) { this.options = options; using (var scope = serviceProvider.CreateScope()) { var registeredHandlers = scope.ServiceProvider.GetServices <IHandler>(); foreach (var svc in registeredHandlers) { var serviceType = svc.GetType(); var interfaceType = serviceType.GetTypeInfo().ImplementedInterfaces.Where(i => typeof(IHandler).IsAssignableFrom(i) && i != typeof(IHandler)).Single(); var interfaceTypeNormalized = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType; var typeNameArray = serviceType.FullName.Split('.'); var resourceName = typeNameArray[typeNameArray.Length - 2].ToLower(); var handlerNameAttribute = serviceType.GetCustomAttribute <HandlerNameAttribute>(); var handlerName = handlerNameAttribute == null ? "" : $"/{handlerNameAttribute.Name.ToLower()}"; if (!resourceHandlers.ContainsKey(resourceName)) { resourceHandlers.Add(resourceName, new Dictionary <string, HandlerInfo>(StringComparer.OrdinalIgnoreCase)); } var handlerKey = $"{HandlerTypeMetadata.Handlers[interfaceTypeNormalized].Key}{handlerName}"; resourceHandlers[resourceName][handlerKey] = new HandlerInfo { HandlerType = serviceType, Method = interfaceType.GetMethod("Handle"), ArgumentTypes = interfaceType.GetMethod("Handle").GetParameters().Select(p => p.ParameterType).ToList(), Key = handlerKey, Resource = resourceName, NormalizedInterfaceType = interfaceTypeNormalized }; } } }
async Task <IActionResult> ExecuteHandler(HandlerInfo handlerInfo, string key, object body = null, bool lookup = false) { var handlerInstance = await serviceProvider.GetHandlerInstance(handlerInfo); if (handlerInfo.NormalizedInterfaceType == typeof(ISearchyHandler)) { var searchyRequest = new SearchyRequest(Request.QueryString.Value); var result = await handlerInstance.Invoke(searchyRequest, lookup, null); if (lookup) { return(StatusCode(206, result)); } return(Ok(result)); } else if (handlerInfo.NormalizedInterfaceType == typeof(IQueryHandler)) { var result = await handlerInstance.Invoke(); return(Ok(result)); } else if (handlerInfo.NormalizedInterfaceType == typeof(IQueryHandler <>)) { var request = Request.Query.GetInstance(handlerInfo.ArgumentTypes[0]); var result = await handlerInstance.Invoke(request); return(Ok(result)); } else if (handlerInfo.NormalizedInterfaceType == typeof(IQueryHandler <,>)) { object keyParam; try { keyParam = key.ConvertValueToType(handlerInfo.ArgumentTypes[0]); } catch (Exception ex) { throw new BadInputFormatException(ex); } var request = Request.Query.GetInstance(handlerInfo.ArgumentTypes[1]); var result = await handlerInstance.Invoke(keyParam, request); return(Ok(result)); } else if (handlerInfo.NormalizedInterfaceType == typeof(ICommandHandler)) { var result = await handlerInstance.Invoke(); return(HandleResult(result)); } else if (handlerInfo.NormalizedInterfaceType == typeof(ICommandHandler <>)) { object typedParam; try { typedParam = JsonConvert.DeserializeObject(body.ToString(), handlerInfo.ArgumentTypes[0]); } catch (Exception ex) { throw new BadInputFormatException(ex); } if (!await ValidateInput(typedParam)) { return(BadRequest(ModelState)); } var result = await handlerInstance.Invoke(typedParam); return(HandleResult(result)); } else if (handlerInfo.NormalizedInterfaceType == typeof(ICommandHandler <,>)) { object typedParam; object keyParam; try { keyParam = key.ConvertValueToType(handlerInfo.ArgumentTypes[0]); typedParam = JsonConvert.DeserializeObject(body.ToString(), handlerInfo.ArgumentTypes[1]); } catch (Exception ex) { throw new BadInputFormatException(ex); } if (!await ValidateInput(typedParam)) { return(BadRequest(ModelState)); } var result = await handlerInstance.Invoke(keyParam, typedParam); return(HandleResult(result)); } else if (handlerInfo.NormalizedInterfaceType == typeof(IGetHandler <>)) { object keyParam; try { keyParam = key.ConvertValueToType(handlerInfo.ArgumentTypes[0]); } catch (Exception ex) { throw new BadInputFormatException(ex); } var result = await handlerInstance.Invoke(keyParam, lookup); if (result == null) { return(NotFound()); } if (lookup) { return(StatusCode(206, result)); } return(HandleResult(result)); } else if (handlerInfo.NormalizedInterfaceType == typeof(IDeleteHandler <>)) { object keyParam; try { keyParam = key.ConvertValueToType(handlerInfo.ArgumentTypes[0]); } catch (Exception ex) { throw new BadInputFormatException(ex); } var result = await handlerInstance.Invoke(keyParam); return(Accepted()); } else { return(NotFound()); } }
async public static Task <HandlerInstance> GetHandlerInstance(this IServiceProvider serviceProvider, HandlerInfo handlerInfo) { var handlerInstance = new HandlerInstance { Method = handlerInfo.Method, Instance = serviceProvider.GetService(handlerInfo.HandlerType) }; if (handlerInstance.Instance is null) { throw new SWException($"Could not find required service {handlerInfo.Key} for resource {handlerInfo.Resource}."); } CqApiOptions options = serviceProvider.GetService <CqApiOptions>() ?? new CqApiOptions(); var protectAttribute = handlerInfo.HandlerType.GetCustomAttribute <ProtectAttribute>(); var unprotectAttribute = handlerInfo.HandlerType.GetCustomAttribute <UnprotectAttribute>(); if ((options.ProtectAll && unprotectAttribute == null) || protectAttribute is ProtectAttribute) { var requestContext = serviceProvider.GetRequiredService <RequestContext>(); if (!requestContext.IsValid) { throw new SWUnauthorizedException(); } if (protectAttribute?.RequireRole ?? false) { var prefix = string.IsNullOrWhiteSpace(options.RolePrefix) ? handlerInfo.Resource : $"{options.RolePrefix}.{handlerInfo.Resource}"; var requiredRoles = new string[] { $"{prefix}.{handlerInfo.HandlerType.Name}", $"{prefix}.*" }; if (!requestContext.User.Claims.Any(c => c.Subject.RoleClaimType == ClaimTypes.Role && requiredRoles.Contains(c.Value, StringComparer.OrdinalIgnoreCase))) { throw new SWForbiddenException(); } } } return(handlerInstance); }