Example #1
0
        /// <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);
        }
Example #2
0
 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;
 }
Example #3
0
 /// <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;
 }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        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);
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
        /// <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;
        }
Example #11
0
        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;
        }
Example #13
0
        /// <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);
        }
Example #14
0
        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);
        }
Example #15
0
        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);
        }
Example #16
0
        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");
        }
Example #17
0
        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);
        }
Example #18
0
        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);
        }
Example #19
0
        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>();
        }
Example #20
0
        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>();
        }
Example #21
0
        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);
        }
Example #22
0
        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);
        }
Example #23
0
 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;
 }
Example #26
0
        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");
 }