/// <summary> /// Invokes the specified <paramref name="route"/> with the provided <paramref name="parameters"/>. /// </summary> /// <param name="route">The route that should be invoked.</param> /// <param name="cancellationToken">Cancellation token</param> /// <param name="parameters">The parameters that the route should be invoked with.</param> /// <param name="context">The context of the route that is being invoked.</param> /// <returns>A <see cref="Response"/> instance that represents the result of the invoked route.</returns> public async Task<Response> Invoke(Route route, CancellationToken cancellationToken, DynamicDictionary parameters, NancyContext context) { object result; try { result = await route.Invoke(parameters, cancellationToken).ConfigureAwait(false); } catch(RouteExecutionEarlyExitException earlyExitException) { context.WriteTraceLog( sb => sb.AppendFormat( "[DefaultRouteInvoker] Caught RouteExecutionEarlyExitException - reason {0}", earlyExitException.Reason)); return earlyExitException.Response; } if (!(result is ValueType) && result == null) { context.WriteTraceLog( sb => sb.AppendLine("[DefaultRouteInvoker] Invocation of route returned null")); result = new Response(); } return this.negotiator.NegotiateResponse(result, context); }
public ResolveResult(Route route, DynamicDictionary parameters, Func<NancyContext, Response> before, Action<NancyContext> after, Func<NancyContext, Exception, Response> onError) { this.Route = route; this.Parameters = parameters; this.Before = before; this.After = after; this.OnError = onError; }
/// <summary> /// Initializes a new instance of the <see cref="ResolveResult"/> class, with /// the provided <paramref name="route"/>, <paramref name="parameters"/>, <paramref name="before"/>, /// <paramref name="after"/> and <paramref name="onError"/>. /// </summary> /// <param name="route">The request route instance.</param> /// <param name="parameters">The parameters.</param> /// <param name="before">The before pipeline instance</param> /// <param name="after">The after pipeline instace.</param> /// <param name="onError">The on error interceptor instance.</param> public ResolveResult(Route route, DynamicDictionary parameters, BeforePipeline before, AfterPipeline after, Func<NancyContext, Exception, dynamic> onError) { this.Route = route; this.Parameters = parameters; this.Before = before; this.After = after; this.OnError = onError; }
public void Should_set_path_property_when_instantiated() { //Given, When const string path = "/dummy/path"; var route = new Route(path, null, x => null); // Then route.Path.ShouldEqual(path); }
public void Should_set_action_property_when_instantiated() { //Given, When Func<dynamic, Response> action = x => null; var route = new Route("/", null, null, action); // Then route.Action.ShouldBeSameAs(action); }
public void Should_set_modules_property_when_instantiated() { //Given, When Func<dynamic, Response> action = x => null; var instance = new FakeNancyModuleWithoutBasePath(); var route = new Route("/", null, instance, action); // Then route.Module.ShouldBeSameAs(instance); }
/// <summary> /// Invokes the specified <paramref name="route"/> with the provided <paramref name="parameters"/>. /// </summary> /// <param name="route">The route that should be invoked.</param> /// <param name="parameters">The parameters that the route should be invoked with.</param> /// <param name="context">The context of the route that is being invoked.</param> /// <returns>A <see cref="Response"/> intance that represents the result of the invoked route.</returns> public Response Invoke(Route route, DynamicDictionary parameters, NancyContext context) { var result = route.Invoke(parameters); if (result == null) { context.WriteTraceLog(sb => sb.AppendLine("[DefaultRouteInvoker] Invocation of route returned null")); result = new Response(); } return this.InvokeRouteWithStrategy(result, context); }
public void Should_return_response_from_action_when_invoked() { //Given var expectedResponse = new Response(); Func<object, Response> action = x => expectedResponse; var route = new Route("/", null, null, action); // When var response = route.Invoke(); // Then response.ShouldBeSameAs(expectedResponse); }
public void Should_set_paramters_property_when_instantiated() { //Given, When Func<dynamic, Response> action = x => null; dynamic parameters = new RouteParameters(); parameters.foo = 10; parameters.bar = "value"; var route = new Route("/", parameters, action); // Then ((object)route.Parameters).ShouldBeSameAs((object)parameters); }
/// <summary> /// Invokes the specified <paramref name="route"/> with the provided <paramref name="parameters"/>. /// </summary> /// <param name="route">The route that should be invoked.</param> /// <param name="cancellationToken">Cancellation token</param> /// <param name="parameters">The parameters that the route should be invoked with.</param> /// <param name="context">The context of the route that is being invoked.</param> /// <returns>A <see cref="Response"/> intance that represents the result of the invoked route.</returns> public Task<Response> Invoke(Route route, CancellationToken cancellationToken, DynamicDictionary parameters, NancyContext context) { var tcs = new TaskCompletionSource<Response>(); var result = route.Invoke(parameters, cancellationToken); result.WhenCompleted( completedTask => { var returnResult = completedTask.Result; if (returnResult == null) { context.WriteTraceLog( sb => sb.AppendLine("[DefaultRouteInvoker] Invocation of route returned null")); returnResult = new Response(); } try { var negotiatedResult = this.InvokeRouteWithStrategy(returnResult, context); tcs.SetResult(negotiatedResult); } catch (Exception e) { tcs.SetException(e); } }, faultedTask => { var earlyExitException = GetEarlyExitException(faultedTask); if (earlyExitException != null) { context.WriteTraceLog( sb => sb.AppendFormat( "[DefaultRouteInvoker] Caught RouteExecutionEarlyExitException - reason {0}", earlyExitException.Reason)); tcs.SetResult(earlyExitException.Response); } else { tcs.SetException(faultedTask.Exception); } }); return tcs.Task; }
public static RouteId Create(INancyModule module, Route route) { var routeId = new RouteId { Module = module }; if (!string.IsNullOrEmpty(route.Description.Name)) { routeId.Name = route.Description.Name; } else { routeId.Method = route.Description.Method.ToHttpMethod(); routeId.Path = route.Description.Path.EnsureForwardSlash(); } return routeId; }
private SwaggerRouteData CreateSwaggerRouteData(INancyModule module, Route route, Dictionary<RouteId, MethodInfo> routeHandlers) { var data = new SwaggerRouteData(route.Description.Path, new PathItem()); var routeId = RouteId.Create(module, route); var handler = routeHandlers.ContainsKey(routeId) ? routeHandlers[routeId] : null; var operation = new AnnotatedOperation(route.Description.Name, handler, _modelCatalog); var method = route.Description.Method.ToHttpMethod(); switch (route.Description.Method.ToLowerInvariant()) { case "get": data.PathItem.Get = operation; break; case "post": data.PathItem.Post = operation; break; case "patch": data.PathItem.Patch = operation; break; case "delete": data.PathItem.Delete = operation; break; case "put": data.PathItem.Put = operation; break; case "head": data.PathItem.Head = operation; break; case "options": data.PathItem.Options = operation; break; } if (operation.ResponseType != null) { data.Types.Add(method, operation.ResponseType); } return data; }
/// <summary> /// Invokes the specified <paramref name="route"/> with the provided <paramref name="parameters"/>. /// </summary> /// <param name="route">The route that should be invoked.</param> /// <param name="parameters">The parameters that the route should be invoked with.</param> /// <param name="context">The context of the route that is being invoked.</param> /// <returns>A <see cref="Response"/> intance that represents the result of the invoked route.</returns> public Response Invoke(Route route, DynamicDictionary parameters, NancyContext context) { dynamic result; try { result = route.Invoke(parameters); } catch (RouteExecutionEarlyExitException earlyExitException) { context.WriteTraceLog(sb => sb.AppendFormat("[DefaultRouteInvoker] Caught RouteExecutionEarlyExitException - reason {0}", earlyExitException.Reason)); result = earlyExitException.Response; } if (result == null) { context.WriteTraceLog(sb => sb.AppendLine("[DefaultRouteInvoker] Invocation of route returned null")); result = new Response(); } return this.InvokeRouteWithStrategy(result, context); }
public void Should_invoke_action_with_parameters_when_invoked() { //Given RouteParameters capturedParameters = null; Func<dynamic, Response> action = x => { capturedParameters = x; return null; }; dynamic parameters = new RouteParameters(); parameters.foo = 10; parameters.bar = "value"; var route = new Route("/", parameters, null, action); // When route.Invoke(); // Then capturedParameters.ShouldBeSameAs((object)parameters); }
public void Should_invoke_action_with_parameters_when_invoked() { //Given DynamicDictionary capturedParameters = null; Func<dynamic, CancellationToken, Task<object>> action = (args, ct) => { capturedParameters = args; return Task.FromResult<object>(null); }; dynamic parameters = new DynamicDictionary(); parameters.foo = 10; parameters.bar = "value"; var route = new Route<object>("GET", "/", null, action); // When route.Invoke(parameters, new CancellationToken()); // Then capturedParameters.ShouldBeSameAs((object)parameters); }
public void Should_store_exception_details_if_route_throws() { var errorRoute = new Route("GET", "/", null, x => { throw new NotImplementedException(); }); A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored, A<IRouteCache>.Ignored)).Returns(new ResolveResult(errorRoute, DynamicDictionary.Empty, null, null)); var request = new Request("GET", "/", "http"); var result = this.engine.HandleRequest(request); result.GetExceptionDetails().ShouldContain("NotImplementedException"); }
public void Should_set_status_code_to_500_if_route_throws() { var errorRoute = new Route("GET", "/", null, x => { throw new NotImplementedException(); }); A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored, A<IRouteCache>.Ignored)).Returns(new ResolveResult(errorRoute, DynamicDictionary.Empty, null, null)); var request = new Request("GET", "/", "http"); var result = this.engine.HandleRequest(request); result.Response.StatusCode.ShouldEqual(HttpStatusCode.InternalServerError); }
public void Should_invoke_the_error_request_hook_if_one_exists_when_dispatcher_throws() { // Given var testEx = new Exception(); var errorRoute = new Route("GET", "/", null, (x,c) => { throw testEx; }); var resolvedRoute = new ResolveResult( errorRoute, DynamicDictionary.Empty, null, null, null); A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute); A.CallTo(() => this.requestDispatcher.Dispatch(context, A<CancellationToken>._)) .Returns(TaskHelpers.GetFaultedTask<Response>(testEx)); Exception handledException = null; NancyContext handledContext = null; var errorResponse = new Response(); A.CallTo(() => this.negotiator.NegotiateResponse(A<object>.Ignored, A<NancyContext>.Ignored)) .Returns(errorResponse); Func<NancyContext, Exception, dynamic> routeErrorHook = (ctx, ex) => { handledContext = ctx; handledException = ex; return errorResponse; }; var pipelines = new Pipelines(); pipelines.OnError.AddItemToStartOfPipeline(routeErrorHook); engine.RequestPipelinesFactory = (ctx) => pipelines; var request = new Request("GET", "/", "http"); // When var result = this.engine.HandleRequest(request); // Then Assert.Equal(testEx, handledException); Assert.Equal(result, handledContext); Assert.Equal(result.Response, errorResponse); }
public void Should_add_unhandled_exception_to_context_as_requestexecutionexception() { // Given var routeUnderTest = new Route("GET", "/", null, (x,c) => { throw new Exception(); }); var resolved = new ResolveResult(routeUnderTest, DynamicDictionary.Empty, null, null, null); A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolved); A.CallTo(() => this.routeInvoker.Invoke(A<Route>._, A<CancellationToken>._, A<DynamicDictionary>._, A<NancyContext>._)) .Invokes((x) => routeUnderTest.Action.Invoke(DynamicDictionary.Empty, new CancellationToken())); A.CallTo(() => this.requestDispatcher.Dispatch(context, A<CancellationToken>._)) .Returns(TaskHelpers.GetFaultedTask<Response>(new Exception())); var pipelines = new Pipelines(); pipelines.OnError.AddItemToStartOfPipeline((ctx, exception) => null); engine.RequestPipelinesFactory = (ctx) => pipelines; var request = new Request("GET", "/", "http"); // When var result = this.engine.HandleRequest(request); // Then result.Items.Keys.Contains("ERROR_EXCEPTION").ShouldBeTrue(); result.Items["ERROR_EXCEPTION"].ShouldBeOfType<RequestExecutionException>(); }
public void Should_add_unhandled_exception_to_context_as_requestexecutionexception() { // Given var routeUnderTest = new Route("GET", "/", null, x => { throw new Exception(); }); var resolved = new ResolveResult(routeUnderTest, DynamicDictionary.Empty, null, null); A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolved); var pipelines = new Pipelines(); pipelines.OnError.AddItemToStartOfPipeline((ctx, exception) => null); engine.RequestPipelinesFactory = (ctx) => pipelines; var request = new Request("GET", "/", "http"); // When var result = this.engine.HandleRequest(request); // Then result.Items.Keys.Contains("ERROR_EXCEPTION").ShouldBeTrue(); result.Items["ERROR_EXCEPTION"].ShouldBeOfType<RequestExecutionException>(); }
public void Should_invoke_the_error_request_hook_if_one_exists_when_route_throws() { // Given var testEx = new Exception(); var errorRoute = new Route("GET", "/", null, x => { throw testEx; }); A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(new ResolveResult(errorRoute, DynamicDictionary.Empty, null, null)); Exception handledException = null; NancyContext handledContext = null; var errorResponse = new Response(); Func<NancyContext, Exception, Response> routeErrorHook = (ctx, ex) => { handledContext = ctx; handledException = ex; return errorResponse; }; var pipelines = new Pipelines(); pipelines.OnError.AddItemToStartOfPipeline(routeErrorHook); engine.RequestPipelinesFactory = (ctx) => pipelines; var request = new Request("GET", "/", "http"); // When var result = this.engine.HandleRequest(request); // Then Assert.Equal(testEx, handledException); Assert.Equal(result, handledContext); Assert.Equal(result.Response, errorResponse); }
public void Should_persist_original_exception_in_requestexecutionexception_when_pipeline_is_null() { // Given var expectedException = new Exception(); var routeUnderTest = new Route("GET", "/", null, x => { throw expectedException; }); var resolved = new ResolveResult(routeUnderTest, DynamicDictionary.Empty, null, null); A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolved); var pipelines = new Pipelines { OnError = null }; engine.RequestPipelinesFactory = (ctx) => pipelines; var request = new Request("GET", "/", "http"); // When var result = this.engine.HandleRequest(request); var returnedException = result.Items["ERROR_EXCEPTION"] as RequestExecutionException; // Then returnedException.InnerException.ShouldBeSameAs(expectedException); }
public void Should_invoke_the_error_request_hook_if_one_exists_when_route_throws() { var testEx = new Exception(); var errorRoute = new Route("GET", "/", null, x => { throw testEx; }); A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored, A<IRouteCache>.Ignored)).Returns(new ResolveResult(errorRoute, DynamicDictionary.Empty, null, null)); Exception handledException = null; NancyContext handledContext = null; var errorResponse = new Response(); Func<NancyContext, Exception, Response> routeErrorHook = (ctx, ex) => { handledContext = ctx; handledException = ex; return errorResponse; }; this.engine.OnErrorHook += routeErrorHook; var request = new Request("GET", "/", "http"); var result = this.engine.HandleRequest(request); Assert.Equal(testEx, handledException); Assert.Equal(result, handledContext); Assert.Equal(result.Response, errorResponse); }
private SwaggerRouteData CreateSwaggerRouteData(INancyModule module, Route route, Dictionary<RouteId, MethodInfo> routeHandlers) { var data = new SwaggerRouteData { ApiPath = route.Description.Path, ResourcePath = module.ModulePath.EnsureForwardSlash(), OperationMethod = route.Description.Method.ToHttpMethod(), OperationNickname = route.Description.Name }; var routeId = RouteId.Create(module, route); var handler = routeHandlers.ContainsKey(routeId) ? routeHandlers[routeId] : null; if (handler == null) { data.OperationNotes = "[example]"; // TODO: Insert example how to annotate a route data.OperationSummary = "Warning: no annotated method found for this route"; return data; } foreach (var attr in handler.GetCustomAttributes<RouteAttribute>()) { data.OperationSummary = attr.Summary ?? data.OperationSummary; data.OperationNotes = attr.Notes ?? data.OperationNotes; data.OperationModel = attr.Response ?? data.OperationModel; data.OperationConsumes = attr.Consumes ?? data.OperationConsumes; data.OperationProduces = attr.Produces ?? data.OperationProduces; } data.OperationResponseMessages = handler.GetCustomAttributes<SwaggerResponseAttribute>() .Select(attr => { var msg = new ResponseMessage { Code = (int)attr.Code, Message = attr.Message }; if (attr.Model != null) { msg.ResponseModel = Primitive.IsPrimitive(attr.Model) ? Primitive.FromType(attr.Model).Type : SwaggerConfig.ModelIdConvention(attr.Model); } return msg; }) .ToList(); data.OperationParameters = handler.GetParameters() .Select(CreateSwaggerParameterData) .ToList(); return data; }
private bool ShowRoute(INancyModule module, Route route, Dictionary<RouteId, MethodInfo> routeHandlers) { var routeId = RouteId.Create(module, route); return routeHandlers.ContainsKey(routeId) || !SwaggerAnnotationsConfig.ShowOnlyAnnotatedRoutes; }
public async Task Should_return_response_from_action_when_invoked() { //Given var expectedResponse = new Response(); Func<dynamic, CancellationToken, Task<Response>> action = (args, ct) => Task.FromResult(expectedResponse); var route = new Route<Response>("GET", "/", null, action); // When var response = await route.Invoke(new DynamicDictionary(), new CancellationToken()); // Then response.ShouldBeSameAs(expectedResponse); }
private SwaggerRouteData CreateSwaggerRouteData(INancyModule module, Route route, Dictionary<RouteId, MethodInfo> routeHandlers) { var operation = new Operation() { OperationId = route.Description.Name }; var data = new SwaggerRouteData(route.Description.Path, new PathItem()); var method = route.Description.Method.ToHttpMethod(); switch (route.Description.Method.ToLowerInvariant()) { case "get": data.PathItem.Get = operation; break; case "post": data.PathItem.Post = operation; break; case "patch": data.PathItem.Patch = operation; break; case "delete": data.PathItem.Delete = operation; break; case "put": data.PathItem.Put = operation; break; case "head": data.PathItem.Head = operation; break; case "options": data.PathItem.Options = operation; break; } var routeId = RouteId.Create(module, route); var handler = routeHandlers.ContainsKey(routeId) ? routeHandlers[routeId] : null; if (handler == null) { operation.Description = "[example]"; // TODO: Insert example how to annotate a route operation.Summary = "Warning: no annotated method found for this route"; return data; } Type model = null; foreach (var attr in handler.GetCustomAttributes<RouteAttribute>()) { operation.Summary = attr.Summary ?? operation.Summary; operation.Description = attr.Notes ?? operation.Description; model = attr.Response ?? model; operation.Consumes = attr.Consumes ?? operation.Consumes; operation.Consumes = attr.Produces ?? operation.Produces; } if (model != null) { data.Types.Add(method, model); } operation.Responses = handler.GetCustomAttributes<SwaggerResponseAttribute>() .Select(attr => { var msg = new global::Swagger.ObjectModel.Response() { Description = attr.Message }; //if (attr.Model != null) //{ // msg.ResponseModel = Primitive.IsPrimitive(attr.Model) // ? Primitive.FromType(attr.Model).Type // : SwaggerConfig.ModelIdConvention(attr.Model); //} return Tuple.Create((int)attr.Code, msg); }) .ToDictionary(x => x.Item1.ToString(), x => x.Item2); operation.Parameters = handler.GetParameters() .Select(CreateSwaggerParameterData) .ToList(); return data; }
public NotFoundRouteFixture() { this.route = new NotFoundRoute("GET", "/test"); }