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);
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        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));
        }
コード例 #4
0
        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"));
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        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"));
        }
コード例 #8
0
        /// <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&lt;System.Object&gt;.</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;
                }
            }
        }