Skip to content

Commit

Permalink
Implemented #112
Browse files Browse the repository at this point in the history
  • Loading branch information
Scott Offen committed Nov 18, 2016
1 parent 893bae2 commit ce28222
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 6 deletions.
1 change: 0 additions & 1 deletion src/Grapevine.Tests/Server/RestServerFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using Grapevine.Shared;
using Grapevine.Shared.Loggers;
using NSubstitute;
using NSubstitute.ReturnsExtensions;
using Shouldly;
using Xunit;

Expand Down
28 changes: 28 additions & 0 deletions src/Grapevine.Tests/Server/RouteFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,34 @@ public void InvokesSharedAndNonSharedInstanceMethod()
route1.Invoke(Mocks.HttpContext());
instance.InstanceHits.ShouldBe(3);
}

[Fact]
public void DisposesWhenExceptionIsThrown()
{
var method = typeof(IsDisposeable).GetMethod("TestDisposing");
var route = new Route(method);

IsDisposeable.WasDisposed.ShouldBeFalse();

Should.Throw<Exception>(() => route.Invoke(Mocks.HttpContext()));

IsDisposeable.WasDisposed.ShouldBeTrue();
}

public class IsDisposeable : IDisposable
{
public static bool WasDisposed = false;

public IHttpContext TestDisposing(IHttpContext context)
{
throw new Exception();
}

public void Dispose()
{
WasDisposed = true;
}
}
}

public class MatchesMethod
Expand Down
52 changes: 50 additions & 2 deletions src/Grapevine.Tests/Server/RouterFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void ThrowsExceptionIfRouteFunctionIsNull()
}
}

public class AfterProperty
public class AfterEvent
{
[Fact]
public void ExecutesAfterRouting()
Expand All @@ -104,9 +104,33 @@ public void ExecutesAfterRouting()
executionOrder[0].ShouldBe("function");
executionOrder[1].ShouldBe("after");
}

[Fact]
public void ExecutesOnAfterRoutingAfterRouting()
{
var firingOrder = new List<string>();
var context = Mocks.HttpContext();
RoutingEventHandler one = ctx => { firingOrder.Add("1"); };
RoutingEventHandler two = ctx => { firingOrder.Add("2"); };

var router = new Router().Register(ctx =>
{
context.WasRespondedTo.Returns(true);
return ctx;
});

router.AfterRouting += one;
router.AfterRouting += two;

router.Route(context);

firingOrder.Count.ShouldBe(2);
firingOrder[0].ShouldBe("2");
firingOrder[1].ShouldBe("1");
}
}

public class BeforeProperty
public class BeforeEvent
{
[Fact]
public void ExecutesBeforeRouting()
Expand All @@ -124,6 +148,30 @@ public void ExecutesBeforeRouting()
executionOrder[0].ShouldBe("before");
executionOrder[1].ShouldBe("function");
}

[Fact]
public void ExecutesOnBeforeRoutingBeforeRouting()
{
var firingOrder = new List<string>();
var context = Mocks.HttpContext();
RoutingEventHandler one = ctx => { firingOrder.Add("1"); };
RoutingEventHandler two = ctx => { firingOrder.Add("2"); };

var router = new Router().Register(ctx =>
{
context.WasRespondedTo.Returns(true);
return ctx;
});

router.BeforeRouting += one;
router.BeforeRouting += two;

router.Route(context);

firingOrder.Count.ShouldBe(2);
firingOrder[0].ShouldBe("1");
firingOrder[1].ShouldBe("2");
}
}

public class ContinueRoutingAfterResponseSentProperty
Expand Down
1 change: 0 additions & 1 deletion src/Grapevine/Server/RestServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,6 @@ public void Stop()
}
}


public static class RestServerExtensions
{
/// <summary>
Expand Down
50 changes: 48 additions & 2 deletions src/Grapevine/Server/Router.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@

namespace Grapevine.Server
{
/// <summary>
/// Delegate for the <see cref="IRouter.BeforeRouting"/> and <see cref="IRouter.AfterRouting"/> events
/// </summary>
/// <param name="context">The <see cref="IHttpContext"/> that is being routed.</param>
public delegate void RoutingEventHandler(IHttpContext context);

/// <summary>
/// Provides a mechanism to register routes and invoke them according to the produced routing table
/// </summary>
Expand All @@ -18,13 +24,25 @@ public interface IRouter
/// <summary>
/// Gets or sets a function to be executed prior to any routes being executed
/// </summary>
[Obsolete("The After delegate has been replace with the AfterRouting event and will be removed in the next version.")]
Func<IHttpContext, IHttpContext> After { get; set; }

/// <summary>
/// Raised after a request has completed invoking matching routes
/// </summary>
event RoutingEventHandler AfterRouting;

/// <summary>
/// Gets or sets a function to be executed after route execution has completed
/// </summary>
[Obsolete("The Before delegate has been replace with the BeforeRouting event and will be removed in the next version.")]
Func<IHttpContext, IHttpContext> Before { get; set; }

/// <summary>
/// Raised prior to sending any request though matching routes
/// </summary>
event RoutingEventHandler BeforeRouting;

/// <summary>
/// Gets or sets a value to indicate whether request routing should continue even after a response has been sent.
/// </summary>
Expand Down Expand Up @@ -275,7 +293,10 @@ public class Router : IRouter
private IGrapevineLogger _logger;

public Func<IHttpContext, IHttpContext> After { get; set; }
public event RoutingEventHandler AfterRouting;

public Func<IHttpContext, IHttpContext> Before { get; set; }
public event RoutingEventHandler BeforeRouting;

public bool ContinueRoutingAfterResponseSent { get; set; }
public string Scope { get; protected set; }
Expand Down Expand Up @@ -533,10 +554,11 @@ public bool Route(IHttpContext context, IList<IRoute> routing)

Logger.BeginRouting($"{context.Request.Id} - {context.Request.Name} has {totalRoutes} routes");

if (Before != null) routeContext = Before.Invoke(routeContext);

try
{
if (Before != null) routeContext = Before.Invoke(routeContext);
OnBeforeRouting(routeContext);

foreach (var route in routing.Where(route => route.Enabled))
{
routeCounter++;
Expand All @@ -550,6 +572,8 @@ public bool Route(IHttpContext context, IList<IRoute> routing)
finally
{
if (After != null) routeContext = After.Invoke(routeContext);
OnAfterRouting(routeContext);

Logger.EndRouting($"{context.Request.Id} - {routeCounter} of {totalRoutes} routes invoked");
}

Expand All @@ -574,5 +598,27 @@ protected void AddToRoutingTable(IEnumerable<IRoute> routes)
{
routes.ToList().ForEach(AddToRoutingTable);
}

/// <summary>
/// Event handler for when the <see cref="BeforeRouting"/> event is raised
/// </summary>
/// <param name="context">The <see cref="IHttpContext"/> being routed</param>
protected void OnBeforeRouting(IHttpContext context)
{
BeforeRouting?.Invoke(context);
}

/// <summary>
/// Event handler for when the <see cref="AfterRouting"/> event is raised
/// </summary>
/// <param name="context">The <see cref="IHttpContext"/> being routed</param>
protected void OnAfterRouting(IHttpContext context)
{
if (AfterRouting == null) return;
foreach (var action in AfterRouting.GetInvocationList().Reverse().Cast<RoutingEventHandler>())
{
action(context);
}
}
}
}

0 comments on commit ce28222

Please sign in to comment.