public async Task InternalServerError_WithMessage_AndException_FriendlyErrorMessage() { var exception = new Exception("Fail"); var actionResult = new InternalServerErrorGraphActionResult("big fail", exception); var context = this.CreateResolutionContext(); await actionResult.Complete(context); Assert.IsTrue(context.IsCancelled); Assert.AreEqual(1, context.Messages.Count); Assert.AreEqual(Constants.ErrorCodes.UNHANDLED_EXCEPTION, context.Messages[0].Code); Assert.AreEqual("big fail", context.Messages[0].Message); Assert.AreEqual(exception, context.Messages[0].Exception); }
public async Task InternalServerError_WithAction_AndException_FriendlyErrorMessage() { var action = TemplateHelper.CreateFieldTemplate <ActionableController>(nameof(ActionableController.DoStuff)) as IGraphMethod; var exception = new Exception("Fail"); var actionResult = new InternalServerErrorGraphActionResult(action, exception); var context = this.CreateResolutionContext(); await actionResult.Complete(context); Assert.IsTrue(context.IsCancelled); Assert.AreEqual(1, context.Messages.Count); Assert.AreEqual(Constants.ErrorCodes.UNHANDLED_EXCEPTION, context.Messages[0].Code); Assert.IsTrue(context.Messages[0].Message.Contains("An unhandled exception was thrown during")); Assert.AreEqual(exception, context.Messages[0].Exception); }
/// <summary> /// Processes the given <see cref="IGraphDirectiveRequest" /> against this instance /// performing the operation as defined by this entity and generating a response. /// </summary> /// <param name="context">The context containing the necessary data to resolve /// the directive and produce a result.</param> /// <param name="cancelToken">The cancel token monitoring the execution of a graph request.</param> /// <returns>Task<IGraphPipelineResponse>.</returns> public async Task Resolve(DirectiveResolutionContext context, CancellationToken cancelToken = default) { var action = _directiveTemplate.FindMethod(context.Request.LifeCycle); // if no action is found skip processing of this directive if (action == null) { return; } IGraphActionResult result; try { // create a scoped controller instance for this invocation var directive = context .ServiceProvider? .GetService(_directiveTemplate.ObjectType) as GraphDirective; if (directive == null) { result = new RouteNotFoundGraphActionResult( $"The directive '{_directiveTemplate.InternalFullName}' " + "was not found in the scoped service provider."); } else { // invoke the right action method and set a result. var task = directive.InvokeActionAsync(action, context); var returnedItem = await task.ConfigureAwait(false); result = this.EnsureGraphActionResult(returnedItem); } } catch (Exception ex) { // :( result = new InternalServerErrorGraphActionResult("Operation failed.", ex); } // resolve the final graph action output using the provided field context // in what ever manner is appropriate for the result itself await result.Complete(context); }
public async Task Resolve(FieldResolutionContext context, CancellationToken cancelToken = default) { IGraphActionResult result; try { // create a scoped controller instance for this invocation var controller = context .ServiceProvider? .GetService(_actionMethod.Parent.ObjectType) as GraphController; if (controller == null) { result = new RouteNotFoundGraphActionResult( $"The controller assigned to process the field '{context.Request.InvocationContext.Field.Route.Path}' " + "was not found."); } else { // invoke the right action method and set a result. var task = controller.InvokeActionAsync(_actionMethod, context); var returnedItem = await task.ConfigureAwait(false); result = this.EnsureGraphActionResult(returnedItem); } } catch (Exception ex) { // :( result = new InternalServerErrorGraphActionResult("Operation failed.", ex); } // resolve the final graph action output using the provided field context // in what ever manner is appropriate for the result itself await result.Complete(context).ConfigureAwait(false); }
/// <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; } } }