コード例 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ActionMethodModelStateValidatedLogEntry" /> class.
        /// </summary>
        /// <param name="method">The method being invoked.</param>
        /// <param name="request">The request being executed on the method.</param>
        /// <param name="modelState">the model dictionary created by the controller.</param>
        public ActionMethodModelStateValidatedLogEntry(
            IGraphMethod method,
            IDataRequest request,
            InputModelStateDictionary modelState)
            : base(LogEventIds.ControllerModelValidated)
        {
            this.PipelineRequestId = request.Id;
            this.ControllerName    = method.Parent.ObjectType?.FriendlyName(true) ?? method.Parent.Name;
            this.ActionName        = method.Name;
            this.FieldPath         = method.Route.Path;
            this.ModelDataIsValid  = modelState.IsValid;
            _shortControllerName   = method.Parent.ObjectType?.FriendlyName() ?? method.Parent.Name;
            this.ModelItems        = null;
            if (modelState.Values != null && modelState.Values.Any())
            {
                var entries = new List <ModelStateEntryLogItem>();
                foreach (var item in modelState.Values)
                {
                    if (item.ValidationState == InputModelValidationState.Invalid)
                    {
                        entries.Add(new ModelStateEntryLogItem(item));
                    }
                }

                this.ModelItems = entries;
            }
        }
コード例 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FieldContextBuilder" /> class.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="user">The user.</param>
        /// <param name="graphField">The graph field.</param>
        /// <param name="schema">The schema.</param>
        /// <param name="graphMethod">The metadata describing the method/functon to be invoked by a resolver.</param>
        public FieldContextBuilder(
            IServiceProvider serviceProvider,
            ClaimsPrincipal user,
            IGraphField graphField,
            ISchema schema,
            IGraphMethod graphMethod)
        {
            _schema            = Validation.ThrowIfNullOrReturn(schema, nameof(schema));
            _graphField        = Validation.ThrowIfNullOrReturn(graphField, nameof(graphField));
            _user              = Validation.ThrowIfNullOrReturn(user, nameof(user));
            _messageCollection = new GraphMessageCollection();

            this.ServiceProvider = Validation.ThrowIfNullOrReturn(serviceProvider, nameof(serviceProvider));

            Type expectedInputType = null;

            if (!Validation.IsCastable <GraphDirective>(graphMethod.Parent.ObjectType) &&
                !Validation.IsCastable <GraphController>(graphMethod.Parent.ObjectType))
            {
                expectedInputType = graphMethod.Parent.ObjectType;
            }

            var metaData = new MetaDataCollection();

            _mockRequest           = new Mock <IGraphFieldRequest>();
            _mockInvocationContext = new Mock <IGraphFieldInvocationContext>();

            // fake the request for the field data (normally generated by the primary query exeuction context)
            var id = Guid.NewGuid().ToString("N");

            _mockRequest.Setup(x => x.Id).Returns(id);
            _mockRequest.Setup(x => x.Origin).Returns(SourceOrigin.None);
            _mockRequest.Setup(x => x.Items).Returns(metaData);
            _mockRequest.Setup(x => x.Field).Returns(_graphField);
            _mockRequest.Setup(x => x.InvocationContext).Returns(_mockInvocationContext.Object);

            _mockInvocationContext.Setup(x => x.ExpectedSourceType).Returns(expectedInputType);
            _mockInvocationContext.Setup(x => x.Field).Returns(_graphField);
            _mockInvocationContext.Setup(x => x.Arguments).Returns(_arguments);
            _mockInvocationContext.Setup(x => x.Name).Returns(_graphField.Name);
            _mockInvocationContext.Setup(x => x.Directives).Returns(new List <IDirectiveInvocationContext>());
            _mockInvocationContext.Setup(x => x.ChildContexts).Returns(new FieldInvocationContextCollection());
            _mockInvocationContext.Setup(x => x.Origin).Returns(SourceOrigin.None);

            this.GraphMethod = new Mock <IGraphMethod>();
            this.GraphMethod.Setup(x => x.Parent).Returns(graphMethod.Parent);
            this.GraphMethod.Setup(x => x.ObjectType).Returns(graphMethod.ObjectType);
            this.GraphMethod.Setup(x => x.ExpectedReturnType).Returns(graphMethod.ExpectedReturnType);
            this.GraphMethod.Setup(x => x.Method).Returns(graphMethod.Method);
            this.GraphMethod.Setup(x => x.IsAsyncField).Returns(graphMethod.IsAsyncField);
            this.GraphMethod.Setup(x => x.Name).Returns(graphMethod.Name);
            this.GraphMethod.Setup(x => x.InternalFullName).Returns(graphMethod.InternalFullName);
            this.GraphMethod.Setup(x => x.InternalName).Returns(graphMethod.InternalName);
            this.GraphMethod.Setup(x => x.Route).Returns(graphMethod.Route);
            this.GraphMethod.Setup(x => x.Arguments).Returns(graphMethod.Arguments);
        }
        private void ValidateModelDictionaryToLogEntry(
            IGraphMethod graphMethod,
            IGraphFieldRequest fieldRequest,
            InputModelStateDictionary dictionary,
            ActionMethodModelStateValidatedLogEntry logEntry)
        {
            Assert.AreEqual(fieldRequest.Id, logEntry.PipelineRequestId);
            Assert.AreEqual(graphMethod.Parent.ObjectType.FriendlyName(true), logEntry.ControllerName);
            Assert.AreEqual(graphMethod.Name, logEntry.ActionName);
            Assert.AreEqual(dictionary.IsValid, logEntry.ModelDataIsValid);

            foreach (var kvp in dictionary)
            {
                var itemResult = kvp.Value;

                if (itemResult.ValidationState == InputModelValidationState.Invalid)
                {
                    var entryResult = logEntry.ModelItems.Cast <ModelStateEntryLogItem>().First(x => itemResult.Name == x.Name);

                    Assert.AreEqual(itemResult.Name, entryResult.Name);
                    Assert.AreEqual(itemResult.ValidationState.ToString(), entryResult.ValidationState);

                    var itemErrors  = itemResult.Errors;
                    var entryErrors = entryResult.Errors;

                    if (itemErrors.Count == 0)
                    {
                        // log entry should skip the property if
                        // no errors are recorded
                        Assert.IsTrue(entryErrors == null);
                        continue;
                    }

                    Assert.AreEqual(itemErrors.Count, entryErrors.Count);

                    for (var i = 0; i < itemErrors.Count; i++)
                    {
                        var itemError  = itemErrors[i];
                        var entryError = entryErrors[i] as ModelStateErrorLogItem;

                        Assert.AreEqual(itemError.ErrorMessage, entryError.ErrorMessage);

                        var itemException  = itemError.Exception;
                        var entryException = entryError.Exception as ExceptionLogItem;

                        Assert.AreEqual(itemException == null, entryException == null);
                        if (itemException != null)
                        {
                            Assert.AreEqual(itemException.Message, entryException.ExceptionMessage);
                            Assert.AreEqual(itemException.StackTrace, entryException.StackTrace);
                            Assert.AreEqual(itemException.GetType().FriendlyName(true), entryException.TypeName);
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ActionMethodInvocationCompletedLogEntry" /> class.
 /// </summary>
 /// <param name="method">The method being invoked.</param>
 /// <param name="request">The request being executed on the method.</param>
 /// <param name="result">The result that was generated.</param>
 public ActionMethodInvocationCompletedLogEntry(IGraphMethod method, IDataRequest request, object result)
     : base(LogEventIds.ControllerInvocationCompleted)
 {
     this.PipelineRequestId = request.Id;
     this.ControllerName    = method.Parent.InternalFullName;
     this.ActionName        = method.InternalName;
     this.FieldPath         = method.Route.Path;
     this.ResultTypeName    = result?.GetType().FriendlyName(true);
     _shortControllerName   = method.Parent.InternalName;
 }
コード例 #5
0
        /// <inheritdoc />
        public virtual void ActionMethodInvocationCompleted(IGraphMethod action, IDataRequest request, object result)
        {
            if (!this.IsEnabled(LogLevel.Trace))
            {
                return;
            }

            var entry = new ActionMethodInvocationCompletedLogEntry(action, request, result);

            this.LogEvent(LogLevel.Trace, entry);
        }
コード例 #6
0
        /// <inheritdoc />
        public virtual void ActionMethodUnhandledException(IGraphMethod action, IDataRequest request, Exception exception)
        {
            if (!this.IsEnabled(LogLevel.Error))
            {
                return;
            }

            var entry = new ActionMethodUnhandledExceptionLogEntry(action, request, exception);

            this.LogEvent(LogLevel.Error, entry);
        }
コード例 #7
0
        /// <inheritdoc />
        public virtual void ActionMethodModelStateValidated(IGraphMethod action, IDataRequest request, InputModelStateDictionary modelState)
        {
            if (!this.IsEnabled(LogLevel.Trace))
            {
                return;
            }

            var entry = new ActionMethodModelStateValidatedLogEntry(action, request, modelState);

            this.LogEvent(LogLevel.Trace, entry);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ActionMethodInvocationExceptionLogEntry" /> class.
 /// </summary>
 /// <param name="method">The method being invoked.</param>
 /// <param name="request">The request being executed on the method.</param>
 /// <param name="exception">The exception that was thrown.</param>
 public ActionMethodInvocationExceptionLogEntry(
     IGraphMethod method,
     IDataRequest request,
     Exception exception)
     : base(
         LogEventIds.ControllerInvocationException,
         method,
         request,
         exception)
 {
 }
コード例 #9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ActionMethodUnhandledExceptionLogEntry" /> class.
 /// </summary>
 /// <param name="method">The method being invoked.</param>
 /// <param name="request">The request being executed on the method.</param>
 /// <param name="exception">The exception that was thrown.</param>
 public ActionMethodUnhandledExceptionLogEntry(
     IGraphMethod method,
     IDataRequest request,
     Exception exception)
     : base(
         LogEventIds.ControllerUnhandledException,
         method,
         request,
         exception)
 {
 }
コード例 #10
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ActionMethodInvocationStartedLogEntry" /> class.
 /// </summary>
 /// <param name="method">The method being invoked.</param>
 /// <param name="request">The request being executed on the method.</param>
 public ActionMethodInvocationStartedLogEntry(IGraphMethod method, IDataRequest request)
     : base(LogEventIds.ControllerInvocationStarted)
 {
     this.PipelineRequestId = request.Id;
     this.ControllerName    = method.Parent.InternalFullName;
     this.ActionName        = method.Name;
     this.FieldPath         = method.Route.Path;
     this.SourceObjectType  = method.ObjectType?.ToString();
     this.IsAsync           = method.IsAsyncField;
     _shortControllerName   = method.Parent.InternalName;
 }
コード例 #11
0
 /// <summary>
 /// Initializes a new instance of the <see cref="BaseActionMethodExceptionLogEntry" /> class.
 /// </summary>
 /// <param name="eventId">The event identifier.</param>
 /// <param name="method">The method being invoked.</param>
 /// <param name="request">The request being executed on the method.</param>
 /// <param name="exception">The exception that was thrown.</param>
 protected BaseActionMethodExceptionLogEntry(
     EventId eventId,
     IGraphMethod method,
     IDataRequest request,
     Exception exception)
     : base(eventId)
 {
     this.PipelineRequestId  = request.Id;
     this.ControllerTypeName = method.Parent.InternalFullName;
     this.ActionName         = method.Name;
     this.Exception          = new ExceptionLogItem(exception);
 }
コード例 #12
0
        /// <summary>
        /// Prepares this colleciton of arguments for use in the provided method invocation generating
        /// a set of values that can be used to invoke the method.
        /// </summary>
        /// <param name="graphMethod">The graph method.</param>
        /// <returns>System.Object[].</returns>
        public object[] PrepareArguments(IGraphMethod graphMethod)
        {
            var paramSet = new List <object>();

            foreach (var argTemplate in graphMethod.Arguments)
            {
                object passedValue = this.ResolveParameterFromArgumentTemplate(argTemplate);
                if (passedValue == null && !argTemplate.TypeExpression.IsNullable)
                {
                    // technically shouldn't be throwable given the validation routines
                    // but captured here as a saftey net for users
                    // doing custom extensions or implementations
                    throw new GraphExecutionException(
                              $"The parameter '{argTemplate.Name}' for field '{graphMethod.Route.Path}' could not be resolved from the query document " +
                              $"or variable collection and no default value was found.");
                }

                paramSet.Add(passedValue);
            }

            return(paramSet.ToArray());
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="InternalServerErrorGraphActionResult" /> class.
 /// </summary>
 /// <param name="action">The action that was invoked to cause this internal error, if any.</param>
 /// <param name="exception">The exception, if any, that was thrown. Useful for logging or other intermediate actions.</param>
 public InternalServerErrorGraphActionResult(IGraphMethod action, Exception exception)
 {
     _action    = action;
     _exception = exception;
 }
コード例 #14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="RouteNotFoundGraphActionResult" /> class.
 /// </summary>
 /// <param name="invokedAction">The invoked action at the route location.</param>
 /// <param name="thrownException">The thrown exception that occured when invoking the action, if any.</param>
 public RouteNotFoundGraphActionResult(IGraphMethod invokedAction, Exception thrownException = null)
 {
     _invokeDef       = invokedAction;
     _thrownException = thrownException;
 }
コード例 #15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GraphObjectMethodResolver" /> class.
 /// </summary>
 /// <param name="graphMethod">The graph method.</param>
 public GraphObjectMethodResolver(IGraphMethod graphMethod)
 {
     _graphMethod = Validation.ThrowIfNullOrReturn(graphMethod, nameof(graphMethod));
     _methodInfo  = _graphMethod.Method;
 }
コード例 #16
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GraphControllerActionResolver"/> class.
 /// </summary>
 /// <param name="actionMethod">The action method that this resolver will invoke.</param>
 public GraphControllerActionResolver(IGraphMethod actionMethod)
 {
     _actionMethod = Validation.ThrowIfNullOrReturn(actionMethod, nameof(actionMethod));
 }
コード例 #17
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;
                }
            }
        }
コード例 #18
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GraphObjectPropertyResolver" /> class.
 /// </summary>
 /// <param name="propertyGetMethod">The property method.</param>
 public GraphObjectPropertyResolver(IGraphMethod propertyGetMethod)
 {
     _graphMethod = Validation.ThrowIfNullOrReturn(propertyGetMethod, nameof(propertyGetMethod));
 }