Add UseWhenExtensions and UseWhenExtensionsTests
This commit is contained in:
parent
62eaf16585
commit
59b605cafb
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Builder
|
||||||
|
{
|
||||||
|
using Predicate = Func<HttpContext, bool>;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="IApplicationBuilder"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class UseWhenExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Conditionally creates a branch in the request pipeline that is rejoined to the main pipeline.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="app"></param>
|
||||||
|
/// <param name="predicate">Invoked with the request environment to determine if the branch should be taken</param>
|
||||||
|
/// <param name="configuration">Configures a branch to take</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IApplicationBuilder UseWhen(this IApplicationBuilder app, Predicate predicate, Action<IApplicationBuilder> configuration)
|
||||||
|
{
|
||||||
|
if (app == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(app));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predicate == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(predicate));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuration == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and configure the branch builder right away; otherwise,
|
||||||
|
// we would end up running our branch after all the components
|
||||||
|
// that were subsequently added to the main builder.
|
||||||
|
var branchBuilder = app.New();
|
||||||
|
configuration(branchBuilder);
|
||||||
|
|
||||||
|
return app.Use(main =>
|
||||||
|
{
|
||||||
|
// This is called only when the main application builder
|
||||||
|
// is built, not per request.
|
||||||
|
branchBuilder.Run(main);
|
||||||
|
var branch = branchBuilder.Build();
|
||||||
|
|
||||||
|
return async context =>
|
||||||
|
{
|
||||||
|
if (predicate(context))
|
||||||
|
{
|
||||||
|
await branch(context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await main(context);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Builder.Internal;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Builder.Extensions
|
||||||
|
{
|
||||||
|
public class UseWhenExtensionsTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void NullArguments_ArgumentNullException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var builder = CreateBuilder();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Action nullPredicate = () => builder.UseWhen(null, app => { });
|
||||||
|
Action nullConfiguration = () => builder.UseWhen(TruePredicate, null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Throws<ArgumentNullException>(nullPredicate);
|
||||||
|
Assert.Throws<ArgumentNullException>(nullConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PredicateTrue_BranchTaken_WillRejoin()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var context = CreateContext();
|
||||||
|
var parent = CreateBuilder();
|
||||||
|
|
||||||
|
parent.UseWhen(TruePredicate, child =>
|
||||||
|
{
|
||||||
|
child.UseWhen(TruePredicate, grandchild =>
|
||||||
|
{
|
||||||
|
grandchild.Use(Increment("grandchild"));
|
||||||
|
});
|
||||||
|
|
||||||
|
child.Use(Increment("child"));
|
||||||
|
});
|
||||||
|
|
||||||
|
parent.Use(Increment("parent"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
parent.Build().Invoke(context).Wait();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1, Count(context, "parent"));
|
||||||
|
Assert.Equal(1, Count(context, "child"));
|
||||||
|
Assert.Equal(1, Count(context, "grandchild"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PredicateTrue_BranchTaken_CanTerminate()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var context = CreateContext();
|
||||||
|
var parent = CreateBuilder();
|
||||||
|
|
||||||
|
parent.UseWhen(TruePredicate, child =>
|
||||||
|
{
|
||||||
|
child.UseWhen(TruePredicate, grandchild =>
|
||||||
|
{
|
||||||
|
grandchild.Use(Increment("grandchild", terminate: true));
|
||||||
|
});
|
||||||
|
|
||||||
|
child.Use(Increment("child"));
|
||||||
|
});
|
||||||
|
|
||||||
|
parent.Use(Increment("parent"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
parent.Build().Invoke(context).Wait();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0, Count(context, "parent"));
|
||||||
|
Assert.Equal(0, Count(context, "child"));
|
||||||
|
Assert.Equal(1, Count(context, "grandchild"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PredicateFalse_PassThrough()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var context = CreateContext();
|
||||||
|
var parent = CreateBuilder();
|
||||||
|
|
||||||
|
parent.UseWhen(FalsePredicate, child =>
|
||||||
|
{
|
||||||
|
child.Use(Increment("child"));
|
||||||
|
});
|
||||||
|
|
||||||
|
parent.Use(Increment("parent"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
parent.Build().Invoke(context).Wait();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1, Count(context, "parent"));
|
||||||
|
Assert.Equal(0, Count(context, "child"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HttpContext CreateContext()
|
||||||
|
{
|
||||||
|
return new DefaultHttpContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ApplicationBuilder CreateBuilder()
|
||||||
|
{
|
||||||
|
return new ApplicationBuilder(serviceProvider: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TruePredicate(HttpContext context)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool FalsePredicate(HttpContext context)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Func<HttpContext, Func<Task>, Task> Increment(string key, bool terminate = false)
|
||||||
|
{
|
||||||
|
return (context, next) =>
|
||||||
|
{
|
||||||
|
if (!context.Items.ContainsKey(key))
|
||||||
|
{
|
||||||
|
context.Items[key] = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var item = context.Items[key];
|
||||||
|
|
||||||
|
if (item is int)
|
||||||
|
{
|
||||||
|
context.Items[key] = 1 + (int)item;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Items[key] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return terminate ? Task.FromResult<object>(null) : next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int Count(HttpContext context, string key)
|
||||||
|
{
|
||||||
|
if (!context.Items.ContainsKey(key))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = context.Items[key];
|
||||||
|
|
||||||
|
if (item is int)
|
||||||
|
{
|
||||||
|
return (int)item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue