Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Implemented. Issue #688 #756

Merged
merged 5 commits into from

3 participants

@andreichuk

Added the OnError hook to NancyModule

(now from the feature branch. The one from the master branch was closed)

@andreichuk andreichuk Implemented. Issue #688
Added the OnError hook to NancyModule
bfd9d33
@prabirshrestha

Can't this already be done using ErrorHandlers? This is how I been handling errors for api.

    public class Api500ErrorHandler : IErrorHandler
    {
        private readonly IEnumerable<ISerializer> serializers;

        public Api500ErrorHandler(IEnumerable<ISerializer> serializers)
        {
            this.serializers = serializers;
        }

        public bool HandlesStatusCode(HttpStatusCode statusCode, NancyContext context)
        {
            return statusCode == HttpStatusCode.InternalServerError && context.Request.Path.StartsWith("/api/");
        }

        public void Handle(HttpStatusCode statusCode, NancyContext context)
        {
            var serializer = serializers.First(s => s.CanSerialize("application/json"));

            var error = new
            {
                message = "Unknown error occurred",
#if DEBUG
                stackTrace = context.Items["ERROR_TRACE"]
#endif
            };

            var response = new JsonResponse(new { error }, serializer)
                               {
                                   StatusCode = HttpStatusCode.InternalServerError
                               };

            context.Response = response;
        }
    }
@thecodejunkie

@prabirshrestha this is per-module error handling though. Makes sense to have it in I think. I think the name perhaps should be Error or Errors instead of OnErrors because that

  • does not follow the naming convention we use in Nancy
  • this ain't no ASP.NET! ;)
@andreichuk

@prabirshrestha, example where ErrorHandler would not help. Here I want ISessionManager to be disposed on exception

public abstract class DbModule : NancyModule
    {
        private readonly ISessionManager _sessionManager;

        protected DbModule(ISessionManager sessionManager, String path)
            : base(path)
        {
            _sessionManager = sessionManager;
            After.AddItemToEndOfPipeline(SaveDbChanges);
            OnError.AddItemToEndOfPipeline(DisposeSession);
        }

        private void SaveDbChanges(NancyContext context)
        {
            _sessionManager.Commit();
            _sessionManager.Dispose();
        }

        private Response DisposeSession(NancyContext context, Exception exception)
        {
            _sessionManager.Rollback();
            _sessionManager.Dispose();

            return null;
        }
    }

It is also is possible to dispose ISessionManager at the Bootstrapper's OnError hook -- but I think it's much better to have Module's OnError hook to handle such situations

@thecodejunkie

1) About the naming convention. Interface Pipelines has property OnError -- so I decided to use this name for the property

public interface IPipelines
    {
        AfterPipeline AfterRequest { get; set; }
        BeforePipeline BeforeRequest { get; set; }
        ErrorPipeline OnError { get; set; }
    }

2) Some description of Module's OnError hook. If it's methods do not return Response -- the exception is rethrown to be handled at Bootstrapper level.

@thecodejunkie

@andreichuk could you please rebase this pull-request?

@andreichuk

okay, no problem. i think i'll do it this weekend -- have no time now :(

@andreichuk

done

@thecodejunkie thecodejunkie merged commit 9a52cd6 into NancyFx:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 19, 2012
  1. @andreichuk

    Implemented. Issue #688

    andreichuk authored
    Added the OnError hook to NancyModule
Commits on Sep 26, 2012
  1. @thecodejunkie

    Merge pull request #765 from prabirshrestha/fixOwinTests

    thecodejunkie authored
    removed version check for owin in unit test
Commits on Sep 28, 2012
  1. @andreichuk

    Implemented. Issue #688

    andreichuk authored
    Added the OnError hook to NancyModule
  2. @andreichuk

    Rebased

    andreichuk authored
  3. @andreichuk

    Removed unnecessary space

    andreichuk authored
This page is out of date. Refresh to see the latest.
View
4 src/Nancy.Tests/Fakes/FakeRouteResolver.cs
@@ -1,7 +1,7 @@
namespace Nancy.Tests.Fakes
{
using Nancy.Routing;
- using ResolveResult = System.Tuple<Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>>;
+ using ResolveResult = System.Tuple<Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>, System.Func<NancyContext, System.Exception, Response>>;
public class FakeRouteResolver : IRouteResolver
{
@@ -11,7 +11,7 @@ public class FakeRouteResolver : IRouteResolver
ResolveResult IRouteResolver.Resolve(NancyContext context)
{
- return new ResolveResult(new FakeRoute(), new DynamicDictionary(), null, null);
+ return new ResolveResult(new FakeRoute(), new DynamicDictionary(), null, null, null);
}
}
}
View
12 src/Nancy.Tests/Unit/NancyEngineFixture.cs
@@ -9,7 +9,7 @@ namespace Nancy.Tests.Unit
using Nancy.Routing;
using Nancy.Tests.Fakes;
using Xunit;
- using ResolveResult = System.Tuple<Nancy.Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>>;
+ using ResolveResult = System.Tuple<Nancy.Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>, System.Func<NancyContext, System.Exception, Response>>;
public class NancyEngineFixture
{
@@ -39,7 +39,7 @@ public NancyEngineFixture()
contextFactory = A.Fake<INancyContextFactory>();
A.CallTo(() => contextFactory.Create()).Returns(context);
- A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(new ResolveResult(route, DynamicDictionary.Empty, null, null));
+ A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(new ResolveResult(route, DynamicDictionary.Empty, null, null, null));
var applicationPipelines = new Pipelines();
@@ -328,6 +328,7 @@ public void Should_set_status_code_to_500_if_route_throws()
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -351,6 +352,7 @@ public void Should_store_exception_details_if_dispatcher_throws()
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -379,6 +381,7 @@ public void Should_invoke_the_error_request_hook_if_one_exists_when_dispatcher_t
errorRoute,
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -420,7 +423,7 @@ public void Should_add_unhandled_exception_to_context_as_requestexecutionexcepti
new Route("GET", "/", null, x => { throw new Exception(); });
var resolved =
- new ResolveResult(routeUnderTest, DynamicDictionary.Empty, null, null);
+ new ResolveResult(routeUnderTest, DynamicDictionary.Empty, null, null, null);
A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolved);
@@ -455,6 +458,7 @@ public void Should_persist_original_exception_in_requestexecutionexception()
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -483,6 +487,7 @@ public void Should_add_requestexecutionexception_to_context_when_pipeline_is_nul
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -512,6 +517,7 @@ public void Should_persist_original_exception_in_requestexecutionexception_when_
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
View
197 src/Nancy.Tests/Unit/Routing/DefaultRequestDispatcherFixture.cs
@@ -8,7 +8,7 @@ namespace Nancy.Tests.Unit.Routing
using Nancy.Responses.Negotiation;
using Nancy.Routing;
using Xunit;
- using ResolveResult = System.Tuple<Nancy.Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>>;
+ using ResolveResult = System.Tuple<Nancy.Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>, System.Func<NancyContext, System.Exception, Response>>;
public class DefaultRequestDispatcherFixture
{
@@ -35,6 +35,7 @@ public DefaultRequestDispatcherFixture()
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>._)).Returns(resolvedRoute);
@@ -55,11 +56,12 @@ public void Should_invoke_module_before_hook_followed_by_resolved_route_followed
}
};
- var resolvedRoute = new ResolveResult(
+ var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => { capturedExecutionOrder.Add("Prehook"); return null; },
- ctx => capturedExecutionOrder.Add("Posthook"));
+ ctx => capturedExecutionOrder.Add("Posthook"),
+ null);
A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -90,14 +92,15 @@ public void Should_not_invoke_resolved_route_if_module_before_hook_returns_respo
}
};
- var resolvedRoute = new ResolveResult(
+ var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => {
capturedExecutionOrder.Add("Prehook");
return new Response();
},
- ctx => capturedExecutionOrder.Add("Posthook"));
+ ctx => capturedExecutionOrder.Add("Posthook"),
+ null);
A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -120,11 +123,12 @@ public void Should_return_response_from_module_before_hook_when_not_null()
var route = new FakeRoute();
- var resolvedRoute = new ResolveResult(
+ var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => moduleBeforeHookResponse,
- ctx => { });
+ ctx => { },
+ null);
A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -146,11 +150,12 @@ public void Should_allow_module_after_hook_to_change_response()
var route = new FakeRoute();
- var resolvedRoute = new ResolveResult(
+ var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => null,
- ctx => ctx.Response = moduleAfterHookResponse);
+ ctx => ctx.Response = moduleAfterHookResponse,
+ null);
A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -170,11 +175,12 @@ public void HandleRequest_should_allow_module_after_hook_to_add_items_to_context
// Given
var route = new FakeRoute();
- var resolvedRoute = new ResolveResult(
+ var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => null,
- ctx => ctx.Items.Add("RoutePostReq", new object()));
+ ctx => ctx.Items.Add("RoutePostReq", new object()),
+ null);
A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
@@ -206,6 +212,7 @@ public void Should_set_the_route_parameters_from_resolved_route()
new FakeRoute(),
parameters,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context)).Returns(resolvedRoute);
@@ -251,6 +258,7 @@ public void Should_invoke_route_resolver_with_path_when_path_does_not_contain_fi
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context))
@@ -289,6 +297,7 @@ public void Should_invoke_route_resolver_with_passed_in_accept_headers_when_path
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context))
@@ -334,6 +343,7 @@ public void Should_invoke_route_resolver_with_extension_stripped_from_path_when_
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context))
@@ -363,6 +373,7 @@ public void Should_invoke_route_resolver_with_path_containing_when_path_does_con
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context))
@@ -416,6 +427,7 @@ public void Should_invoke_route_resolver_with_distinct_mapped_media_ranged_when_
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context))
@@ -457,6 +469,7 @@ public void Should_set_quality_to_high_for_mapped_media_ranges_before_invoking_r
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context))
@@ -485,6 +498,7 @@ public void Should_call_route_invoker_with_resolved_route()
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context)).Returns(resolvedRoute);
@@ -523,6 +537,7 @@ public void Should_invoke_route_resolver_with_path_containing_extension_when_map
new NotFoundRoute("GET", "/"),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context))
@@ -552,6 +567,7 @@ public void Should_call_route_invoker_with_captured_parameters()
new FakeRoute(),
parameters,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context)).Returns(resolvedRoute);
@@ -577,6 +593,7 @@ public void Should_call_route_invoker_with_context()
new FakeRoute(),
DynamicDictionary.Empty,
null,
+ null,
null);
A.CallTo(() => this.routeResolver.Resolve(context)).Returns(resolvedRoute);
@@ -587,5 +604,163 @@ public void Should_call_route_invoker_with_context()
// Then
A.CallTo(() => this.routeInvoker.Invoke(A<Route>._, A<DynamicDictionary>._, context)).MustHaveHappened(Repeated.Exactly.Once);
}
+
+ [Fact]
+ public void Should_invoke_module_onerror_hook_when_module_before_hook_throws_exception()
+ {
+ // Given
+ var capturedExecutionOrder = new List<string>();
+ var expectedExecutionOrder = new[] { "Prehook", "OnErrorHook" };
+
+ var route = new FakeRoute
+ {
+ Action = parameters =>
+ {
+ capturedExecutionOrder.Add("RouteInvoke");
+ return null;
+ }
+ };
+
+ var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
+ route,
+ DynamicDictionary.Empty,
+ ctx => { capturedExecutionOrder.Add("Prehook"); throw new Exception("Prehook"); },
+ ctx => capturedExecutionOrder.Add("Posthook"),
+ (ctx, ex) => { capturedExecutionOrder.Add("OnErrorHook"); return new Response(); });
+
+ A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
+
+ var context =
+ new NancyContext { Request = new Request("GET", "/", "http") };
+
+ // When
+ this.requestDispatcher.Dispatch(context);
+
+ // Then
+ capturedExecutionOrder.Count().ShouldEqual(2);
+ capturedExecutionOrder.SequenceEqual(expectedExecutionOrder).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void Should_invoke_module_onerror_hook_when_route_invoker_throws_exception()
+ {
+ // Given
+ var capturedExecutionOrder = new List<string>();
+ var expectedExecutionOrder = new[] { "RouteInvoke", "OnErrorHook" };
+
+ var route = new FakeRoute
+ {
+ Action = parameters =>
+ {
+ capturedExecutionOrder.Add("RouteInvoke");
+ throw new Exception("RouteInvoke");
+ }
+ };
+
+ var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
+ route,
+ DynamicDictionary.Empty,
+ ctx => null,
+ ctx => capturedExecutionOrder.Add("Posthook"),
+ (ctx, ex) => { capturedExecutionOrder.Add("OnErrorHook"); return new Response(); });
+
+ A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
+
+ var context =
+ new NancyContext { Request = new Request("GET", "/", "http") };
+
+ // When
+ this.requestDispatcher.Dispatch(context);
+
+ // Then
+ capturedExecutionOrder.Count().ShouldEqual(2);
+ capturedExecutionOrder.SequenceEqual(expectedExecutionOrder).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void Should_invoke_module_onerror_hook_when_module_after_hook_throws_exception()
+ {
+ // Given
+ var capturedExecutionOrder = new List<string>();
+ var expectedExecutionOrder = new[] { "Posthook", "OnErrorHook" };
+
+ var route = new FakeRoute
+ {
+ Action = parameters => null
+ };
+
+ var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
+ route,
+ DynamicDictionary.Empty,
+ ctx => null,
+ ctx => { capturedExecutionOrder.Add("Posthook"); throw new Exception("Posthook"); },
+ (ctx, ex) => { capturedExecutionOrder.Add("OnErrorHook"); return new Response(); });
+
+ A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
+
+ var context =
+ new NancyContext { Request = new Request("GET", "/", "http") };
+
+ // When
+ this.requestDispatcher.Dispatch(context);
+
+ // Then
+ capturedExecutionOrder.Count().ShouldEqual(2);
+ capturedExecutionOrder.SequenceEqual(expectedExecutionOrder).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void Should_rethrow_exception_when_onerror_hook_does_return_response()
+ {
+ // Given
+ var route = new FakeRoute
+ {
+ Action = parameters => { throw new Exception(); }
+ };
+
+ var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
+ route,
+ DynamicDictionary.Empty,
+ ctx => null,
+ ctx => { },
+ (ctx, ex) => { return null; });
+
+ A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
+
+ var context =
+ new NancyContext { Request = new Request("GET", "/", "http") };
+
+ //When
+
+ // Then
+ Assert.Throws<Exception>(() => this.requestDispatcher.Dispatch(context));
+ }
+
+ [Fact]
+ public void Should_not_rethrow_exception_when_onerror_hook_returns_response()
+ {
+ // Given
+ var route = new FakeRoute
+ {
+ Action = parameters => { throw new Exception(); }
+ };
+
+ var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
+ route,
+ DynamicDictionary.Empty,
+ ctx => null,
+ ctx => { },
+ (ctx, ex) => { return new Response(); });
+
+ A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);
+
+ var context =
+ new NancyContext { Request = new Request("GET", "/", "http") };
+
+ //When
+
+ // Then
+ Assert.DoesNotThrow(() => this.requestDispatcher.Dispatch(context));
+ }
}
}
View
13 src/Nancy/NancyModule.cs
@@ -35,6 +35,7 @@ protected NancyModule(string modulePath)
{
this.After = new AfterPipeline();
this.Before = new BeforePipeline();
+ this.OnError = new ErrorPipeline();
this.ModulePath = modulePath;
this.routes = new List<Route>();
}
@@ -63,6 +64,18 @@ protected NancyModule(string modulePath)
public BeforePipeline Before { get; protected set; }
/// <summary>
+ /// <para>
+ /// The error hook
+ /// </para>
+ /// <para>
+ /// The error hook is called if an exception is thrown at any time during executing
+ /// the PreRequest hook, a route and the PostRequest hook. It can be used to set
+ /// the response and/or finish any ongoing tasks (close database session, etc).
+ /// </para>
+ /// </summary>
+ public ErrorPipeline OnError { get; protected set; }
+
+ /// <summary>
/// Gets or sets the current Nancy context
/// </summary>
/// <value>A <see cref="NancyContext"/> instance.</value>
View
50 src/Nancy/Routing/DefaultRequestDispatcher.cs
@@ -5,7 +5,7 @@ namespace Nancy.Routing
using System.IO;
using System.Linq;
using Responses.Negotiation;
- using ResolveResult = System.Tuple<Nancy.Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>>;
+ using ResolveResult = System.Tuple<Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>, System.Func<NancyContext, System.Exception, Response>>;
/// <summary>
/// Default implementation of a request dispatcher.
@@ -41,21 +41,30 @@ public void Dispatch(NancyContext context)
context.Parameters = resolveResult.Item2;
var resolveResultPreReq = resolveResult.Item3;
var resolveResultPostReq = resolveResult.Item4;
- ExecuteRoutePreReq(context, resolveResultPreReq);
+ var resolveResultOnError = resolveResult.Item5;
- if (context.Response == null)
+ try
{
- context.Response = this.routeInvoker.Invoke(resolveResult.Item1, resolveResult.Item2, context);
- }
+ ExecuteRoutePreReq(context, resolveResultPreReq);
- if (context.Request.Method.ToUpperInvariant() == "HEAD")
- {
- context.Response = new HeadResponse(context.Response);
- }
+ if (context.Response == null)
+ {
+ context.Response = this.routeInvoker.Invoke(resolveResult.Item1, resolveResult.Item2, context);
+ }
+
+ if (context.Request.Method.ToUpperInvariant() == "HEAD")
+ {
+ context.Response = new HeadResponse(context.Response);
+ }
- if (resolveResultPostReq != null)
+ if (resolveResultPostReq != null)
+ {
+ resolveResultPostReq.Invoke(context);
+ }
+ }
+ catch (Exception exception)
{
- resolveResultPostReq.Invoke(context);
+ ExecuteRouteOnError(context, resolveResultOnError, exception);
}
}
@@ -74,6 +83,25 @@ private static void ExecuteRoutePreReq(NancyContext context, Func<NancyContext,
}
}
+ private static void ExecuteRouteOnError(NancyContext context, Func<NancyContext, Exception, Response> resolveResultOnError, Exception exception)
+ {
+ if (resolveResultOnError == null)
+ {
+ return;
+ }
+
+ var resolveResultOnErrorResponse = resolveResultOnError.Invoke(context, exception);
+
+ if (resolveResultOnErrorResponse != null)
+ {
+ context.Response = resolveResultOnErrorResponse;
+ }
+ else
+ {
+ throw exception;
+ }
+ }
+
private ResolveResult Resolve(NancyContext context)
{
var extension =
View
16 src/Nancy/Routing/DefaultRouteResolver.cs
@@ -6,7 +6,7 @@
using Diagnostics;
using Responses.Negotiation;
using RouteCandidate = System.Tuple<string, int, RouteDescription, IRoutePatternMatchResult>;
- using ResolveResult = System.Tuple<Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>>;
+ using ResolveResult = System.Tuple<Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>, System.Func<NancyContext, System.Exception, Response>>;
/// <summary>
/// The default implementation for deciding if any of the available routes is a match for the incoming HTTP request.
@@ -40,7 +40,7 @@ public DefaultRouteResolver(INancyModuleCatalog nancyModuleCatalog, IRoutePatter
/// Gets the route, and the corresponding parameter dictionary from the URL
/// </summary>
/// <param name="context">Current context</param>
- /// <returns>Tuple - Item1 being the Route, Item2 being the parameters dictionary, Item3 being the prereq, Item4 being the postreq</returns>
+ /// <returns>Tuple - Item1 being the Route, Item2 being the parameters dictionary, Item3 being the prereq, Item4 being the postreq, Item5 being the error handler</returns>
public ResolveResult Resolve(NancyContext context)
{
var result =
@@ -56,7 +56,7 @@ private ResolveResult CreateRouteAndParametersFromMatch(NancyContext context, Ro
var route = associatedModule.Routes.ElementAt(routeMatchToReturn.Item2);
- return new ResolveResult(route, routeMatchToReturn.Item4.Parameters, associatedModule.Before, associatedModule.After);
+ return new ResolveResult(route, routeMatchToReturn.Item4.Parameters, associatedModule.Before, associatedModule.After, associatedModule.OnError);
}
private NancyModule GetInitializedModuleForMatch(NancyContext context, RouteCandidate routeMatchToReturn)
@@ -105,7 +105,7 @@ private ResolveResults Resolve(string path, NancyContext context, IRouteCache ro
context.Trace.TraceLog.WriteLog(s => s.AppendLine("[DefaultRouteResolver] No routes available"));
return new ResolveResults
{
- Selected = new ResolveResult(new NotFoundRoute(context.Request.Method, path), DynamicDictionary.Empty, null, null)
+ Selected = new ResolveResult(new NotFoundRoute(context.Request.Method, path), DynamicDictionary.Empty, null, null, null)
};
}
@@ -129,7 +129,7 @@ private ResolveResults Resolve(string path, NancyContext context, IRouteCache ro
context.Trace.TraceLog.WriteLog(s => s.AppendLine("[DefaultRouteResolver] No route had a valid condition"));
return new ResolveResults
{
- Selected = new ResolveResult(new NotFoundRoute(context.Request.Method, path), DynamicDictionary.Empty, null, null),
+ Selected = new ResolveResult(new NotFoundRoute(context.Request.Method, path), DynamicDictionary.Empty, null, null, null),
Rejected = routes.Item2
};
}
@@ -154,7 +154,7 @@ private ResolveResults Resolve(string path, NancyContext context, IRouteCache ro
context.Trace.TraceLog.WriteLog(s => s.AppendLine("[DefaultRouteResolver] No route matched the requested path"));
return new ResolveResults
{
- Selected = new ResolveResult(new NotFoundRoute(context.Request.Method, path), DynamicDictionary.Empty, null, null),
+ Selected = new ResolveResult(new NotFoundRoute(context.Request.Method, path), DynamicDictionary.Empty, null, null, null),
Rejected = routes.Item2
};
}
@@ -184,14 +184,14 @@ private ResolveResults Resolve(string path, NancyContext context, IRouteCache ro
{
return new ResolveResults
{
- Selected = new ResolveResult(new OptionsRoute(context.Request.Path, allowedMethods), DynamicDictionary.Empty, null, null),
+ Selected = new ResolveResult(new OptionsRoute(context.Request.Path, allowedMethods), DynamicDictionary.Empty, null, null, null),
Rejected = routes.Item2
};
}
context.Trace.TraceLog.WriteLog(s => s.AppendLine("[DefaultRouteResolver] Route Matched But Method Not Allowed"));
return new ResolveResults
{
- Selected = new ResolveResult(new MethodNotAllowedRoute(path, context.Request.Method, allowedMethods), DynamicDictionary.Empty, null, null),
+ Selected = new ResolveResult(new MethodNotAllowedRoute(path, context.Request.Method, allowedMethods), DynamicDictionary.Empty, null, null, null),
Rejected = routes.Item2
};
}
View
6 src/Nancy/Routing/IRouteResolver.cs
@@ -1,7 +1,7 @@
namespace Nancy.Routing
{
using System;
- using ResolveResult = System.Tuple<Nancy.Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>>;
+ using ResolveResult = System.Tuple<Nancy.Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>, System.Func<NancyContext, System.Exception, Response>>;
/// <summary>
/// Returns a route that matches the request
@@ -12,7 +12,7 @@ public interface IRouteResolver
/// Gets the route, and the corresponding parameter dictionary from the URL
/// </summary>
/// <param name="context">Current context</param>
- /// <returns>Tuple - Item1 being the Route, Item2 being the parameters dictionary, Item3 being the prereq, Item4 being the postreq</returns>
- ResolveResult Resolve(NancyContext context);
+ /// <returns>Tuple - Item1 being the Route, Item2 being the parameters dictionary, Item3 being the prereq, Item4 being the postreq, Item5 being the error handler</returns>
+ ResolveResult Resolve(NancyContext context);
}
}
Something went wrong with that request. Please try again.