public void ValidModelItem_BuildsLogEntry() { var server = new TestServerBuilder() .AddGraphType <LogTestController>() .Build(); var builder = server.CreateFieldContextBuilder <LogTestController>(nameof(LogTestController.ValidatableInputObject)); var context = builder.CreateExecutionContext(); // valid range 0 - 35 var item = new ValidatableObject() { Age = 18, }; var generator = new ModelStateGenerator(); var argumentToTest = CreateArgument("testItem", item); var dictionary = generator.CreateStateDictionary(argumentToTest); var entry = new ActionMethodModelStateValidatedLogEntry( builder.GraphMethod.Object, context.Request, dictionary); this.ValidateModelDictionaryToLogEntry(builder.GraphMethod.Object, context.Request, dictionary, entry); }
public void ComplexValueProperties_ValidModelItem_ReportValidState() { var item = new ValidatiableComplexPropertyObject() { Child = new ValidatiableScalarPropertyObject() { NullableProperty = null, RangeProperty = 7, RequiredLengthProperty = "abc123", RequiredProperty = "b", }, RangeValue = 33, }; var generator = new ModelStateGenerator(); var argumentToTest = CreateArgument("testItem", item); var dictionary = generator.CreateStateDictionary(argumentToTest); Assert.IsTrue(dictionary.IsValid); Assert.AreEqual(1, dictionary.Count); Assert.IsTrue(dictionary.ContainsKey("testItem")); var entry = dictionary["testItem"]; Assert.AreEqual(0, entry.Errors.Count); }
public async Task BadRequest_WithModelDictionary_RendersMessageOnResponse() { var server = new TestServerBuilder().Build(); var methodTemplate = TemplateHelper.CreateFieldTemplate <ActionableController>(nameof(ActionableController.DoStuff)); var argTemplate = methodTemplate.Arguments[0]; var fieldArg = new GraphArgumentMaker(server.Schema).CreateArgument(argTemplate).Argument; // name is marked required, will fail var dataItem = new ActionableModelItem() { Name = null, Id = "5", }; var arg = new ExecutionArgument(fieldArg, dataItem); var col = new ExecutionArgumentCollection(); col.Add(arg); var generator = new ModelStateGenerator(); var modelDictionary = generator.CreateStateDictionary(col); var actionResult = new BadRequestGraphActionResult(modelDictionary); var context = this.CreateResolutionContext(); await actionResult.Complete(context); Assert.IsNull(context.Result); Assert.IsTrue(context.Messages.Any(x => x.Code == Constants.ErrorCodes.BAD_REQUEST)); Assert.IsTrue(context.Messages.Any(x => x.Code == Constants.ErrorCodes.MODEL_VALIDATION_ERROR)); }
public void ListAsModelValue_ScalarElementsEachCheckedForValidity_ReportsCorrectly() { var enumerable = new[] { "string1", "string2", "string3" } as IEnumerable <string>; var generator = new ModelStateGenerator(); var argumentToTest = CreateArgument("testItem", enumerable, typeof(ValidatiableScalarPropertyObject), MetaGraphTypes.IsList); var dictionary = generator.CreateStateDictionary(argumentToTest); Assert.IsTrue(dictionary.IsValid); Assert.AreEqual(1, dictionary.Count); Assert.IsTrue(dictionary.ContainsKey("testItem")); }
public void NullAsModelValue_ReportsSkipped() { var generator = new ModelStateGenerator(); var argumentToTest = CreateArgument("testItem", null, typeof(ValidatiableScalarPropertyObject)); var dictionary = generator.CreateStateDictionary(argumentToTest); Assert.IsTrue(dictionary.IsValid); Assert.AreEqual(1, dictionary.Count); Assert.IsTrue(dictionary.ContainsKey("testItem")); var entry = dictionary["testItem"]; Assert.AreEqual(InputModelValidationState.Skipped, entry.ValidationState); }
public void ScalarValueProperties_InvalidModelItem_ReportInvalidState() { var item = new ValidatiableScalarPropertyObject() { NullableProperty = null, RangeProperty = -15, // out of range RequiredLengthProperty = "abc123", RequiredProperty = "b", }; var generator = new ModelStateGenerator(); var argumentToTest = CreateArgument("testItem", item); var dictionary = generator.CreateStateDictionary(argumentToTest); Assert.IsFalse(dictionary.IsValid); Assert.AreEqual(1, dictionary.Count); Assert.IsTrue(dictionary.ContainsKey("testItem")); var entry = dictionary["testItem"]; Assert.AreEqual(1, entry.Errors.Count); Assert.AreEqual("RangeProperty", entry.Errors[0].MemberName); }
public void ComplexValueProperties_InValidChildModelItem_ReportValidState() { // by default no children properties should checked. so even if rangedproperty is invalid its // not checked (requires custom attributes by the developer) var item = new ValidatiableComplexPropertyObject() { Child = new ValidatiableScalarPropertyObject() { NullableProperty = null, RangeProperty = -15, // out of range RequiredLengthProperty = "abc123", RequiredProperty = "b", }, RangeValue = 33, }; var generator = new ModelStateGenerator(); var argumentToTest = CreateArgument("testItem", item); var dictionary = generator.CreateStateDictionary(argumentToTest); Assert.IsTrue(dictionary.IsValid); Assert.AreEqual(1, dictionary.Count); Assert.IsTrue(dictionary.ContainsKey("testItem")); }
/// <summary> /// Invoke the specified action method as an asynchronous operation. /// </summary> /// <param name="actionToInvoke">The action to invoke.</param> /// <param name="context">The context.</param> /// <returns>Task<System.Object>.</returns> public async Task <object> InvokeActionAsync( IGraphMethod actionToInvoke, BaseResolutionContext <TRequest> context) { // deconstruct the context for processing _action = actionToInvoke; var fieldRequest = context.Request; this.Request = Validation.ThrowIfNullOrReturn(fieldRequest, nameof(fieldRequest)); _context = context; _logger = context?.Logger; _logger?.ActionMethodInvocationRequestStarted(_action, this.Request); if (_action?.Method == null) { return(new InternalServerErrorGraphActionResult( $"The definition for field '{this.GetType().Name}' defined no graph action to execute. Operation failed.")); } try { var modelGenerator = new ModelStateGenerator(context.ServiceProvider); this.ModelState = modelGenerator.CreateStateDictionary(context.Arguments); _logger?.ActionMethodModelStateValidated(_action, this.Request, this.ModelState); if (_action.Method.DeclaringType != this.GetType()) { throw new TargetException($"Unable to invoke action '{_action.Route.Path}' on controller '{this.GetType().FriendlyName()}'. The controller " + "does not own the method."); } var invoker = InstanceFactory.CreateInstanceMethodInvoker(_action.Method); var invocationParameters = context.Arguments.PrepareArguments(_action); var invokeReturn = invoker(this, invocationParameters); if (_action.IsAsyncField) { if (invokeReturn is Task task) { await task.ConfigureAwait(false); if (task.IsFaulted) { throw task.UnwrapException(); } invokeReturn = task.ResultOrDefault(); } else { // given all the checking and parsing this should be imnpossible, but just in case invokeReturn = new InternalServerErrorGraphActionResult($"The action '{_action.Route.Path}' is defined " + $"as asyncronous but it did not return a {typeof(Task)}."); } } _logger?.ActionMethodInvocationCompleted(_action, this.Request, invokeReturn); return(invokeReturn); } catch (TargetInvocationException ti) { var innerException = ti.InnerException ?? ti; _logger?.ActionMethodInvocationException(_action, this.Request, innerException); return(new InternalServerErrorGraphActionResult(_action, innerException)); } catch (Exception ex) { switch (ex) { // catch any other invocation exceptions and treat them as an invalid route // might happen if a method was declared differently than the actual call signature case TargetException _: case TargetParameterCountException _: _logger?.ActionMethodInvocationException(_action, this.Request, ex); return(new RouteNotFoundGraphActionResult(_action, ex)); default: // total failure by the user's action code. // record and bubble _logger?.ActionMethodUnhandledException(_action, this.Request, ex); throw; } } }