Skip to content

Add new Use middleware extension method #31784

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Components/WebAssembly/DevServer/src/Server/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ private static void EnableConfiguredPathbase(IApplicationBuilder app, IConfigura
{
if (context.Request.PathBase == pathBase)
{
return next();
return next(context);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static IApplicationBuilder UseBlazorFrameworkFiles(this IApplicationBuild
context.Response.Headers.Append("DOTNET-MODIFIABLE-ASSEMBLIES", Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES"));
}

await next();
await next(context);
});

subBuilder.UseMiddleware<ContentEncodingNegotiator>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static void UseWebAssemblyDebugging(this IApplicationBuilder app)
{
app.Map("/_framework/debug", app =>
{
app.Use(async (context, next) =>
app.Run(async (context) =>
{
var queryParams = HttpUtility.ParseQueryString(context.Request.QueryString.Value!);
var browserParam = queryParams.Get("browser");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, BootReso
{
bootResourceRequestLog.AddRequest(context.Request);
}
return next();
return next(context);
});

if (env.IsDevelopment())
Expand Down
2 changes: 1 addition & 1 deletion src/Components/test/testassets/TestServer/ServerStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, Resource
resourceRequestLog.AddRequest(context.Request);
}

return next();
return next(context);
});

app.UseStaticFiles();
Expand Down
6 changes: 3 additions & 3 deletions src/Hosting/TestHost/test/TestServerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public void ConfigureContainer(ThirdPartyContainer container) =>
container.Services.AddSingleton(new TestService { Message = "ConfigureContainer" });

public void Configure(IApplicationBuilder app) =>
app.Use((ctx, next) => ctx.Response.WriteAsync(
app.Run(ctx => ctx.Response.WriteAsync(
$"{ctx.RequestServices.GetRequiredService<SimpleService>().Message}, {ctx.RequestServices.GetRequiredService<TestService>().Message}"));
}

Expand Down Expand Up @@ -472,7 +472,7 @@ public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
app.Use(async (context, nxt) =>
{
context.Features.Set<IServiceProvidersFeature>(this);
await nxt();
await nxt(context);
});
next(app);
};
Expand Down Expand Up @@ -514,7 +514,7 @@ public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
app.Use(async (context, nxt) =>
{
context.Features.Set<IServiceProvidersFeature>(this);
await nxt();
await nxt(context);
});
next(app);
};
Expand Down
24 changes: 23 additions & 1 deletion src/Http/Http.Abstractions/src/Extensions/UseExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,19 @@ public static class UseExtensions
{
/// <summary>
/// Adds a middleware delegate defined in-line to the application's request pipeline.
/// If you aren't calling the next function, use <see cref="RunExtensions.Run(IApplicationBuilder, RequestDelegate)"/> instead.
/// <para>
/// Prefer using <see cref="Use(IApplicationBuilder, Func{HttpContext, RequestDelegate, Task})"/> for better performance as shown below:
/// <code>
/// app.Use((context, next) =>
/// {
/// return next(context);
/// });
/// </code>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add a quip about preferring Run if next is unused?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

/// </para>
/// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> instance.</param>
/// <param name="middleware">A function that handles the request or calls the given next function.</param>
/// <param name="middleware">A function that handles the request and calls the given next function.</param>
/// <returns>The <see cref="IApplicationBuilder"/> instance.</returns>
public static IApplicationBuilder Use(this IApplicationBuilder app, Func<HttpContext, Func<Task>, Task> middleware)
{
Expand All @@ -29,5 +39,17 @@ public static IApplicationBuilder Use(this IApplicationBuilder app, Func<HttpCon
};
});
}

/// <summary>
/// Adds a middleware delegate defined in-line to the application's request pipeline.
/// If you aren't calling the next function, use <see cref="RunExtensions.Run(IApplicationBuilder, RequestDelegate)"/> instead.
/// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> instance.</param>
/// <param name="middleware">A function that handles the request and calls the given next function.</param>
/// <returns>The <see cref="IApplicationBuilder"/> instance.</returns>
public static IApplicationBuilder Use(this IApplicationBuilder app, Func<HttpContext, RequestDelegate, Task> middleware)
{
return app.Use(next => context => middleware(context, next));
}
}
}
1 change: 1 addition & 0 deletions src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ Microsoft.AspNetCore.Http.Metadata.IFromServiceMetadata
Microsoft.AspNetCore.Http.Endpoint.Endpoint(Microsoft.AspNetCore.Http.RequestDelegate? requestDelegate, Microsoft.AspNetCore.Http.EndpointMetadataCollection? metadata, string? displayName) -> void
Microsoft.AspNetCore.Http.Endpoint.RequestDelegate.get -> Microsoft.AspNetCore.Http.RequestDelegate?
Microsoft.AspNetCore.Routing.RouteValueDictionary.TryAdd(string! key, object? value) -> bool
static Microsoft.AspNetCore.Builder.UseExtensions.Use(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, System.Func<Microsoft.AspNetCore.Http.HttpContext!, Microsoft.AspNetCore.Http.RequestDelegate!, System.Threading.Tasks.Task!>! middleware) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
static Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.UseMiddleware(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, System.Type! middleware, params object?[]! args) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
static Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.UseMiddleware<TMiddleware>(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, params object?[]! args) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
80 changes: 80 additions & 0 deletions src/Http/Http.Abstractions/test/UseExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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.Http;
using Xunit;

namespace Microsoft.AspNetCore.Builder.Extensions
{
public class UseExtensionsTests
{
[Fact]
public async Task UseCallsNextMiddleware()
{
// Arrange
var builder = new ApplicationBuilder(serviceProvider: null!);
var context = new DefaultHttpContext();
var firstCalled = false;
var secondCalled = false;
var lastCalled = false;

builder.Use((context, next) =>
{
firstCalled = true;
return next();
});
builder.Use((context, next) =>
{
Assert.True(firstCalled);
secondCalled = true;
return next(context);
});
builder.Run(context =>
{
Assert.True(secondCalled);
lastCalled = true;
return Task.CompletedTask;
});

// Act
await builder.Build().Invoke(context);

// Assert
Assert.True(firstCalled);
Assert.True(secondCalled);
Assert.True(lastCalled);
}

[Fact]
public async Task ThrowFromMiddlewareFlowsBackToInvoke()
{
// Arrange
var builder = new ApplicationBuilder(serviceProvider: null!);
var context = new DefaultHttpContext();
var shouldThrow = true;

builder.Use(async (context, next) =>
{
throw await Assert.ThrowsAsync<Exception>(() => next());
});
builder.Use(async (context, next) =>
{
throw await Assert.ThrowsAsync<Exception>(() => next(context));
});
builder.Run(context =>
{
if (shouldThrow)
{
throw new Exception("From Use");
}
return Task.CompletedTask;
});

// Act & Assert
var ex = await Assert.ThrowsAsync<Exception>(() => builder.Build().Invoke(context));
Assert.Equal("From Use", ex.Message);
}
}
}
2 changes: 1 addition & 1 deletion src/Http/Http/test/ApplicationBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public async Task BuildImplicitlyThrowsForMatchedEndpointAsLastStep()
public void BuildDoesNotCallMatchedEndpointWhenTerminated()
{
var builder = new ApplicationBuilder(null);
builder.Use((context, next) =>
builder.Run(context =>
{
// Do not call next
return Task.CompletedTask;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
Expand Down Expand Up @@ -31,7 +31,7 @@ public void Configure(IApplicationBuilder app)
});

routes.MapGet("api/get/{id}", (request, response, routeData) => response.WriteAsync($"API Get {routeData.Values["id"]}"))
.MapMiddlewareRoute("api/middleware", (appBuilder) => appBuilder.Use((httpContext, next) => httpContext.Response.WriteAsync("Middleware!")))
.MapMiddlewareRoute("api/middleware", (appBuilder) => appBuilder.Run(httpContext => httpContext.Response.WriteAsync("Middleware!")))
.MapRoute(
name: "AllVerbs",
template: "api/all/{name}/{lastName?}",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
Expand Down Expand Up @@ -31,7 +31,7 @@ public void Configure(IApplicationBuilder app)
});

routes.MapGet("api/get/{id}", (request, response, routeData) => response.WriteAsync($"API Get {routeData.Values["id"]}"))
.MapMiddlewareRoute("api/middleware", (appBuilder) => appBuilder.Use((httpContext, next) => httpContext.Response.WriteAsync("Middleware!")))
.MapMiddlewareRoute("api/middleware", (appBuilder) => appBuilder.Run(httpContext => httpContext.Response.WriteAsync("Middleware!")))
.MapRoute(
name: "AllVerbs",
template: "api/all/{name}/{lastName?}",
Expand Down
2 changes: 1 addition & 1 deletion src/Identity/test/InMemory.Test/FunctionalTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ private static async Task<TestServer> CreateServer(Action<IServiceCollection> co
}
else
{
await next();
await next(context);
}
});
})
Expand Down
2 changes: 1 addition & 1 deletion src/Middleware/CORS/test/UnitTests/CorsMiddlewareTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ public async Task CorsRequest_SetsResponseHeader_IfExceptionHandlerClearsRespons
{
try
{
await next();
await next(context);
}
catch (Exception)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public async Task DoesNotHandle_UnhandledExceptions_WhenResponseAlreadyStarted()
Exception exception = null;
try
{
await next();
await next(httpContext);
}
catch (InvalidOperationException ex)
{
Expand Down Expand Up @@ -143,7 +143,7 @@ public async Task ClearsResponseBuffer_BeforeRequestIsReexecuted()

try
{
await next();
await next(httpContext);
}
finally
{
Expand Down Expand Up @@ -328,7 +328,7 @@ public async Task DoesNotClearCacheHeaders_WhenResponseHasAlreadyStarted()
Exception exception = null;
try
{
await next();
await next(httpContext);
}
catch (InvalidOperationException ex)
{
Expand Down Expand Up @@ -483,7 +483,7 @@ public async Task ExceptionHandlerNotFound_ThrowsIOEWithOriginalError()
Exception exception = null;
try
{
await next();
await next(httpContext);
}
catch (InvalidOperationException ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public async Task Reexecute_CanRetrieveInformationAboutOriginalRequest()
app.Use(async (context, next) =>
{
var beforeNext = context.Request.QueryString;
await next();
await next(context);
var afterNext = context.Request.QueryString;

Assert.Equal(beforeNext, afterNext);
Expand Down Expand Up @@ -150,7 +150,7 @@ public async Task Reexecute_ClearsEndpointAndRouteData()
{
Assert.Empty(context.Request.RouteValues);
Assert.Null(context.GetEndpoint());
return next();
return next(context);
});

app.Map(destination, (innerAppBuilder) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void Configure(IApplicationBuilder app)
"Endpoint display name");

context.SetEndpoint(endpoint);
return next();
return next(context);
});
app.UseDeveloperExceptionPage();
app.Run(context =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void Configure(IApplicationBuilder app)
}
else
{
await next();
await next(context);
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task AllowsMissingHost(bool allowed, int status)
app.Use((ctx, next) =>
{
ctx.Request.Headers.Remove(HeaderNames.Host);
return next();
return next(ctx);
});
app.UseHostFiltering();
app.Run(c =>
Expand Down Expand Up @@ -102,7 +102,7 @@ public async Task AllowsEmptyHost(bool allowed, int status)
app.Use((ctx, next) =>
{
ctx.Request.Headers[HeaderNames.Host] = "";
return next();
return next(ctx);
});
app.UseHostFiltering();
app.Run(c =>
Expand Down Expand Up @@ -159,7 +159,7 @@ public async Task AllowsSpecifiedHost(string hosturl, string allowedHost)
// TestHost's ClientHandler doesn't let you set the host header, only the host in the URI
// and that would over-normalize some of our test conditions like casing.
ctx.Request.Headers[HeaderNames.Host] = hosturl;
return next();
return next(ctx);
});
app.UseHostFiltering();
app.Run(c => Task.CompletedTask);
Expand Down Expand Up @@ -211,7 +211,7 @@ public async Task RejectsMismatchedHosts(string hosturl, string allowedHost)
// TestHost's ClientHandler doesn't let you set the host header, only the host in the URI
// and that would reject some of our test conditions.
ctx.Request.Headers[HeaderNames.Host] = hosturl;
return next();
return next(ctx);
});
app.UseHostFiltering();
app.Run(c => throw new NotImplementedException("App"));
Expand Down Expand Up @@ -250,7 +250,7 @@ public async Task SupportsDynamicOptionsReload()
app.Use((ctx, next) =>
{
ctx.Request.Headers[HeaderNames.Host] = currentHost;
return next();
return next(ctx);
});
app.UseHostFiltering();
app.Run(c => Task.CompletedTask);
Expand Down
Loading