private FluentActionValidationResult ValidateFluentActionForBuilding(FluentActionBase fluentAction) { if (fluentAction == null) { throw new ArgumentNullException(nameof(fluentAction)); } var validationResult = new FluentActionValidationResult { Valid = true, ValidationErrorMessages = new List<string>() }; if (fluentAction.Definition == null) { validationResult.AddValidationError($"{nameof(fluentAction.Definition)} is null."); return validationResult; } if (fluentAction.Definition.Handlers == null) { validationResult.AddValidationError($"{nameof(fluentAction.Definition.Handlers)} is null."); return validationResult; } var handlers = fluentAction.Definition.Handlers; if (!handlers.Any()) { validationResult.AddValidationError("At least one handler is required."); } foreach (var handlerWithNoReturnType in handlers.Where(handler => handler.Type != FluentActionHandlerType.Action && handler.ReturnType == null)) { validationResult.AddValidationError("Missing return type for handler."); } if (handlers.Any() && handlers.Last().Type == FluentActionHandlerType.Action) { validationResult.AddValidationError("Cannot end a fluent action with a Do statement."); } return validationResult; }
public FluentActionControllerDefinition Build(FluentActionBase fluentAction, ILogger logger = null) { if (fluentAction == null) { throw new ArgumentNullException(nameof(fluentAction)); } var validationResult = ValidateFluentActionForBuilding(fluentAction); if (!validationResult.Valid) { throw new FluentActionValidationException($"Could not validate fluent action {fluentAction}: {validationResult}"); } if (fluentAction.Definition.IsMapRoute) { var handler = fluentAction.Definition.Handlers.First(); if (handler.Expression == null) { throw new ArgumentException( $"Missing action expression for {fluentAction}."); } if (!(handler.Expression.Body is MethodCallExpression)) { throw new ArgumentException( $"Expression for {fluentAction} must be a single method call expression."); } var method = ((MethodCallExpression)handler.Expression.Body).Method; var controllerTypeInfo = method.DeclaringType.GetTypeInfo(); if (!typeof(Controller).IsAssignableFrom(controllerTypeInfo.UnderlyingSystemType)) { throw new ArgumentException( $"Method call for {fluentAction} must come from a controller."); } var guid = Guid.NewGuid().ToString().Without("-"); return new FluentActionControllerDefinition() { Id = controllerTypeInfo.Name + "_" + method.Name + "_" + guid, Name = controllerTypeInfo.Name, ActionName = method.Name, FluentAction = fluentAction, TypeInfo = controllerTypeInfo }; } else { if ( ( fluentAction.Definition.GroupName != null || fluentAction.Definition.IgnoreApi == true ) && fluentAction.Definition.CustomAttributes.All(ca => ca.Type != typeof(ApiExplorerSettingsAttribute)) ) { var nonNullableProperties = new Dictionary<string, object>() { { "GroupName", fluentAction.Definition.GroupName }, { "IgnoreApi", fluentAction.Definition.IgnoreApi }, } .Where(pair => pair.Value != null) .ToList(); var apiExplorerSettingsAttributeType = typeof(ApiExplorerSettingsAttribute); fluentAction.Definition.CustomAttributes.Add(new FluentActionCustomAttribute { Type = apiExplorerSettingsAttributeType, Constructor = apiExplorerSettingsAttributeType.GetConstructor(new Type[0]), ConstructorArgs = new object[0], NamedProperties = nonNullableProperties.Select(p => apiExplorerSettingsAttributeType.GetProperty(p.Key)).ToArray(), PropertyValues = nonNullableProperties.Select(p => p.Value).ToArray(), NamedFields = new FieldInfo[0], FieldValues = new object[0], }); } try { var controllerTypeInfo = DefineControllerType(fluentAction.Definition, logger); return new FluentActionControllerDefinition() { Id = controllerTypeInfo.Name, Name = controllerTypeInfo.Name, ActionName = ActionName, FluentAction = fluentAction, TypeInfo = controllerTypeInfo }; } catch (Exception buildException) { throw new Exception($"Could not build controller type for {fluentAction}: {buildException.Message}", buildException); } } }