From 0f424a4f976f3f2d52b0f33ec02d82922dd57bc6 Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Thu, 7 Apr 2022 16:43:37 -0700 Subject: [PATCH 01/35] Adding ResultsOfT --- src/Http/Http.Results/src/Accepted.cs | 76 ++ src/Http/Http.Results/src/AcceptedAtRoute.cs | 83 ++ ...uteHttpResult.cs => AcceptedAtRouteOfT.cs} | 22 +- .../{AcceptedHttpResult.cs => AcceptedOfT.cs} | 21 +- src/Http/Http.Results/src/BadRequest.cs | 40 + ...stObjectHttpResult.cs => BadRequestOfT.cs} | 16 +- .../{ChallengeHttpResult.cs => Challenge.cs} | 28 +- src/Http/Http.Results/src/Conflict.cs | 40 + ...lictObjectHttpResult.cs => ConflictOfT.cs} | 16 +- .../src/{ContentHttpResult.cs => Content.cs} | 20 +- src/Http/Http.Results/src/Created.cs | 73 ++ src/Http/Http.Results/src/CreatedAtRoute.cs | 82 ++ ...outeHttpResult.cs => CreatedAtRouteOfT.cs} | 23 +- .../{CreatedHttpResult.cs => CreatedOfT.cs} | 21 +- .../src/{EmptyHttpResult.cs => Empty.cs} | 10 +- ...ileContentHttpResult.cs => FileContent.cs} | 16 +- .../src/{ForbidHttpResult.cs => Forbid.cs} | 28 +- ...eStreamHttpResult.cs => HttpFileStream.cs} | 16 +- .../Http.Results/src/HttpResultsHelper.cs | 16 +- .../src/{JsonHttpResult.cs => Json.cs} | 29 +- .../{NoContentHttpResult.cs => NoContent.cs} | 8 +- src/Http/Http.Results/src/NotFound.cs | 39 + ...oundObjectHttpResult.cs => NotFoundOfT.cs} | 16 +- src/Http/Http.Results/src/ObjectHttpResult.cs | 80 -- src/Http/Http.Results/src/Ok.cs | 41 + .../src/{OkObjectHttpResult.cs => OkOfT.cs} | 16 +- ...sicalFileHttpResult.cs => PhysicalFile.cs} | 18 +- .../src/{ProblemHttpResult.cs => Problem.cs} | 17 +- ...{PushStreamHttpResult.cs => PushStream.cs} | 16 +- .../{RedirectHttpResult.cs => Redirect.cs} | 20 +- ...oRouteHttpResult.cs => RedirectToRoute.cs} | 32 +- src/Http/Http.Results/src/Results.Typed.cs | 852 ++++++++++++++++++ src/Http/Http.Results/src/Results.cs | 75 +- .../src/{SignInHttpResult.cs => SignIn.cs} | 12 +- .../src/{SignOutHttpResult.cs => SignOut.cs} | 28 +- .../{StatusCodeHttpResult.cs => Status.cs} | 8 +- ...uthorizedHttpResult.cs => Unauthorized.cs} | 8 +- .../Http.Results/src/UnprocessableEntity.cs | 38 + ...ttpResult.cs => UnprocessableEntityOfT.cs} | 16 +- ...irtualFileHttpResult.cs => VirtualFile.cs} | 16 +- .../test/AcceptedAtRouteResultTests.cs | 8 +- .../Http.Results/test/AcceptedResultTests.cs | 6 +- .../test/BadRequestObjectResultTests.cs | 8 +- .../test/ConflictObjectResultTest.cs | 8 +- .../test/CreatedAtRouteResultTests.cs | 6 +- .../test/FileContentResultTest.cs | 2 +- .../Http.Results/test/FileStreamResultTest.cs | 8 +- .../Http.Results/test/ForbidResultTest.cs | 8 +- .../test/LocalRedirectResultTest.cs | 12 +- .../Http.Results/test/NoContentResultTests.cs | 4 +- .../test/NotFoundObjectResultTest.cs | 8 +- .../Http.Results/test/ObjectResultTests.cs | 2 +- .../Http.Results/test/OkObjectResultTest.cs | 6 +- .../test/PhysicalFileResultTest.cs | 2 +- .../Http.Results/test/ProblemResultTests.cs | 6 +- .../Http.Results/test/PushStreamResultTest.cs | 6 +- .../Http.Results/test/RedirectResultTest.cs | 4 +- .../test/RedirectToRouteResultTest.cs | 8 +- .../Http.Results/test/SignInResultTest.cs | 6 +- .../Http.Results/test/SignOutResultTest.cs | 6 +- .../test/StatusCodeResultTests.cs | 2 +- .../test/UnauthorizedResultTests.cs | 4 +- .../UnprocessableEntityObjectResultTests.cs | 8 +- .../test/VirtualFileResultTest.cs | 2 +- src/submodules/googletest | 2 +- 65 files changed, 1746 insertions(+), 428 deletions(-) create mode 100644 src/Http/Http.Results/src/Accepted.cs create mode 100644 src/Http/Http.Results/src/AcceptedAtRoute.cs rename src/Http/Http.Results/src/{AcceptedAtRouteHttpResult.cs => AcceptedAtRouteOfT.cs} (86%) rename src/Http/Http.Results/src/{AcceptedHttpResult.cs => AcceptedOfT.cs} (81%) create mode 100644 src/Http/Http.Results/src/BadRequest.cs rename src/Http/Http.Results/src/{BadRequestObjectHttpResult.cs => BadRequestOfT.cs} (76%) rename src/Http/Http.Results/src/{ChallengeHttpResult.cs => Challenge.cs} (79%) create mode 100644 src/Http/Http.Results/src/Conflict.cs rename src/Http/Http.Results/src/{ConflictObjectHttpResult.cs => ConflictOfT.cs} (76%) rename src/Http/Http.Results/src/{ContentHttpResult.cs => Content.cs} (75%) create mode 100644 src/Http/Http.Results/src/Created.cs create mode 100644 src/Http/Http.Results/src/CreatedAtRoute.cs rename src/Http/Http.Results/src/{CreatedAtRouteHttpResult.cs => CreatedAtRouteOfT.cs} (86%) rename src/Http/Http.Results/src/{CreatedHttpResult.cs => CreatedOfT.cs} (80%) rename src/Http/Http.Results/src/{EmptyHttpResult.cs => Empty.cs} (64%) rename src/Http/Http.Results/src/{FileContentHttpResult.cs => FileContent.cs} (90%) rename src/Http/Http.Results/src/{ForbidHttpResult.cs => Forbid.cs} (80%) rename src/Http/Http.Results/src/{FileStreamHttpResult.cs => HttpFileStream.cs} (91%) rename src/Http/Http.Results/src/{JsonHttpResult.cs => Json.cs} (74%) rename src/Http/Http.Results/src/{NoContentHttpResult.cs => NoContent.cs} (84%) create mode 100644 src/Http/Http.Results/src/NotFound.cs rename src/Http/Http.Results/src/{NotFoundObjectHttpResult.cs => NotFoundOfT.cs} (75%) delete mode 100644 src/Http/Http.Results/src/ObjectHttpResult.cs create mode 100644 src/Http/Http.Results/src/Ok.cs rename src/Http/Http.Results/src/{OkObjectHttpResult.cs => OkOfT.cs} (77%) rename src/Http/Http.Results/src/{PhysicalFileHttpResult.cs => PhysicalFile.cs} (91%) rename src/Http/Http.Results/src/{ProblemHttpResult.cs => Problem.cs} (77%) rename src/Http/Http.Results/src/{PushStreamHttpResult.cs => PushStream.cs} (90%) rename src/Http/Http.Results/src/{RedirectHttpResult.cs => Redirect.cs} (85%) rename src/Http/Http.Results/src/{RedirectToRouteHttpResult.cs => RedirectToRoute.cs} (91%) create mode 100644 src/Http/Http.Results/src/Results.Typed.cs rename src/Http/Http.Results/src/{SignInHttpResult.cs => SignIn.cs} (86%) rename src/Http/Http.Results/src/{SignOutHttpResult.cs => SignOut.cs} (79%) rename src/Http/Http.Results/src/{StatusCodeHttpResult.cs => Status.cs} (86%) rename src/Http/Http.Results/src/{UnauthorizedHttpResult.cs => Unauthorized.cs} (88%) create mode 100644 src/Http/Http.Results/src/UnprocessableEntity.cs rename src/Http/Http.Results/src/{UnprocessableEntityObjectHttpResult.cs => UnprocessableEntityOfT.cs} (77%) rename src/Http/Http.Results/src/{VirtualFileHttpResult.cs => VirtualFile.cs} (92%) diff --git a/src/Http/Http.Results/src/Accepted.cs b/src/Http/Http.Results/src/Accepted.cs new file mode 100644 index 000000000000..b2570c461009 --- /dev/null +++ b/src/Http/Http.Results/src/Accepted.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +/// +/// An that on execution will write an object to the response +/// with status code Accepted (202) and Location header. +/// Targets a registered route. +/// +public sealed class Accepted : IResult +{ + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + /// The location at which the status of requested content can be monitored. + internal Accepted(string? location) + { + Location = location; + } + + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + /// The location at which the status of requested content can be monitored. + internal Accepted(Uri locationUri) + { + if (locationUri == null) + { + throw new ArgumentNullException(nameof(locationUri)); + } + + if (locationUri.IsAbsoluteUri) + { + Location = locationUri.AbsoluteUri; + } + else + { + Location = locationUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped); + } + } + + /// + /// Gets the HTTP status code. + /// + public int StatusCode => StatusCodes.Status202Accepted; + + /// + /// Gets the location at which the status of the requested content can be monitored. + /// + public string? Location { get; } + + /// + public Task ExecuteAsync(HttpContext httpContext) + { + // Creating the logger with a string to preserve the category after the refactoring. + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.AcceptedResult"); + + if (!string.IsNullOrEmpty(Location)) + { + httpContext.Response.Headers.Location = Location; + } + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return Task.CompletedTask; + } +} diff --git a/src/Http/Http.Results/src/AcceptedAtRoute.cs b/src/Http/Http.Results/src/AcceptedAtRoute.cs new file mode 100644 index 000000000000..012a2089fd8c --- /dev/null +++ b/src/Http/Http.Results/src/AcceptedAtRoute.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +/// +/// An that on execution will write an object to the response +/// with status code Accepted (202) and Location header. +/// Targets a registered route. +/// +public sealed class AcceptedAtRoute : IResult +{ + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + /// The route data to use for generating the URL. + internal AcceptedAtRoute(object? routeValues) + : this(routeName: null, routeValues: routeValues) + { + } + + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + internal AcceptedAtRoute( + string? routeName, + object? routeValues) + { + RouteName = routeName; + RouteValues = new RouteValueDictionary(routeValues); + } + + /// + /// Gets the name of the route to use for generating the URL. + /// + public string? RouteName { get; } + + /// + /// Gets the route data to use for generating the URL. + /// + public RouteValueDictionary RouteValues { get; } + + /// + /// Gets the HTTP status code. + /// + public int StatusCode => StatusCodes.Status202Accepted; + + /// + public Task ExecuteAsync(HttpContext httpContext) + { + var linkGenerator = httpContext.RequestServices.GetRequiredService(); + var url = linkGenerator.GetUriByAddress( + httpContext, + RouteName, + RouteValues, + fragment: FragmentString.Empty); + + if (string.IsNullOrEmpty(url)) + { + throw new InvalidOperationException("No route matches the supplied values."); + } + + // Creating the logger with a string to preserve the category after the refactoring. + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.AcceptedAtRouteResult"); + + httpContext.Response.Headers.Location = url; + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return Task.CompletedTask; + } +} diff --git a/src/Http/Http.Results/src/AcceptedAtRouteHttpResult.cs b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs similarity index 86% rename from src/Http/Http.Results/src/AcceptedAtRouteHttpResult.cs rename to src/Http/Http.Results/src/AcceptedAtRouteOfT.cs index 0e45e84164ce..ea95d8b3c62b 100644 --- a/src/Http/Http.Results/src/AcceptedAtRouteHttpResult.cs +++ b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using System.Threading.Tasks; using Microsoft.AspNetCore.Routing; @@ -13,30 +13,30 @@ namespace Microsoft.AspNetCore.Http; /// with status code Accepted (202) and Location header. /// Targets a registered route. /// -public sealed class AcceptedAtRouteHttpResult : IResult +public sealed class AcceptedAtRoute : IResult { /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The route data to use for generating the URL. /// The value to format in the entity body. - internal AcceptedAtRouteHttpResult(object? routeValues, object? value) + internal AcceptedAtRoute(object? routeValues, TValue? value) : this(routeName: null, routeValues: routeValues, value: value) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The value to format in the entity body. - internal AcceptedAtRouteHttpResult( + internal AcceptedAtRoute( string? routeName, object? routeValues, - object? value) + TValue? value) { Value = value; RouteName = routeName; @@ -47,7 +47,7 @@ internal AcceptedAtRouteHttpResult( /// /// Gets the object result. /// - public object? Value { get; } + public TValue? Value { get; } /// /// Gets the name of the route to use for generating the URL. @@ -84,6 +84,10 @@ public Task ExecuteAsync(HttpContext httpContext) var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.AcceptedAtRouteResult"); httpContext.Response.Headers.Location = url; - return HttpResultsHelper.WriteResultAsJsonAsync(httpContext, logger, Value, StatusCode); + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return HttpResultsHelper.WriteResultAsJsonAsync(httpContext, logger, Value); } } diff --git a/src/Http/Http.Results/src/AcceptedHttpResult.cs b/src/Http/Http.Results/src/AcceptedOfT.cs similarity index 81% rename from src/Http/Http.Results/src/AcceptedHttpResult.cs rename to src/Http/Http.Results/src/AcceptedOfT.cs index d0b6026e0c56..68377469a345 100644 --- a/src/Http/Http.Results/src/AcceptedHttpResult.cs +++ b/src/Http/Http.Results/src/AcceptedOfT.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -12,15 +12,15 @@ namespace Microsoft.AspNetCore.Http; /// with status code Accepted (202) and Location header. /// Targets a registered route. /// -public sealed class AcceptedHttpResult : IResult +public sealed class Accepted : IResult { /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The location at which the status of requested content can be monitored. /// The value to format in the entity body. - internal AcceptedHttpResult(string? location, object? value) + internal Accepted(string? location, TValue? value) { Value = value; Location = location; @@ -28,12 +28,12 @@ internal AcceptedHttpResult(string? location, object? value) } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The location at which the status of requested content can be monitored. /// The value to format in the entity body. - internal AcceptedHttpResult(Uri locationUri, object? value) + internal Accepted(Uri locationUri, TValue? value) { Value = value; HttpResultsHelper.ApplyProblemDetailsDefaultsIfNeeded(Value, StatusCode); @@ -56,7 +56,7 @@ internal AcceptedHttpResult(Uri locationUri, object? value) /// /// Gets the object result. /// - public object? Value { get; } + public TValue? Value { get; } /// /// Gets the HTTP status code. @@ -79,10 +79,13 @@ public Task ExecuteAsync(HttpContext httpContext) // Creating the logger with a string to preserve the category after the refactoring. var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.AcceptedResult"); + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger, - Value, - StatusCode); + Value); } } diff --git a/src/Http/Http.Results/src/BadRequest.cs b/src/Http/Http.Results/src/BadRequest.cs new file mode 100644 index 000000000000..4fc267e85ef3 --- /dev/null +++ b/src/Http/Http.Results/src/BadRequest.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +/// +/// An that on execution will write an object to the response +/// with Bad Request (400) status code. +/// +public sealed class BadRequest : IResult +{ + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + internal BadRequest() + { + } + + /// + /// Gets the HTTP status code. + /// + public int StatusCode => StatusCodes.Status400BadRequest; + + /// + public Task ExecuteAsync(HttpContext httpContext) + { + // Creating the logger with a string to preserve the category after the refactoring. + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.BadRequestObjectResult"); + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return Task.CompletedTask; + } +} diff --git a/src/Http/Http.Results/src/BadRequestObjectHttpResult.cs b/src/Http/Http.Results/src/BadRequestOfT.cs similarity index 76% rename from src/Http/Http.Results/src/BadRequestObjectHttpResult.cs rename to src/Http/Http.Results/src/BadRequestOfT.cs index dc9ad6e4fb2f..ae23feb605f8 100644 --- a/src/Http/Http.Results/src/BadRequestObjectHttpResult.cs +++ b/src/Http/Http.Results/src/BadRequestOfT.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,14 +10,14 @@ namespace Microsoft.AspNetCore.Http; /// An that on execution will write an object to the response /// with Bad Request (400) status code. /// -public sealed class BadRequestObjectHttpResult : IResult +public sealed class BadRequest : IResult { /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The error content to format in the entity body. - internal BadRequestObjectHttpResult(object? error) + internal BadRequest(TValue? error) { Value = error; HttpResultsHelper.ApplyProblemDetailsDefaultsIfNeeded(Value, StatusCode); @@ -26,7 +26,7 @@ internal BadRequestObjectHttpResult(object? error) /// /// Gets the object result. /// - public object? Value { get; internal init; } + public TValue? Value { get; } /// /// Gets the HTTP status code. @@ -40,10 +40,12 @@ public Task ExecuteAsync(HttpContext httpContext) var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.BadRequestObjectResult"); + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger: logger, - Value, - StatusCode); + Value); } } diff --git a/src/Http/Http.Results/src/ChallengeHttpResult.cs b/src/Http/Http.Results/src/Challenge.cs similarity index 79% rename from src/Http/Http.Results/src/ChallengeHttpResult.cs rename to src/Http/Http.Results/src/Challenge.cs index cff6c06937dd..dcbe244fd7ca 100644 --- a/src/Http/Http.Results/src/ChallengeHttpResult.cs +++ b/src/Http/Http.Results/src/Challenge.cs @@ -6,72 +6,72 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that on execution invokes . /// -public sealed partial class ChallengeHttpResult : IResult +public sealed partial class Challenge : IResult { /// - /// Initializes a new instance of . + /// Initializes a new instance of . /// - internal ChallengeHttpResult() + internal Challenge() : this(Array.Empty()) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme. /// /// The authentication scheme to challenge. - internal ChallengeHttpResult(string authenticationScheme) + internal Challenge(string authenticationScheme) : this(new[] { authenticationScheme }) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes. /// /// The authentication schemes to challenge. - internal ChallengeHttpResult(IList authenticationSchemes) + internal Challenge(IList authenticationSchemes) : this(authenticationSchemes, properties: null) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified . /// /// used to perform the authentication /// challenge. - internal ChallengeHttpResult(AuthenticationProperties? properties) + internal Challenge(AuthenticationProperties? properties) : this(Array.Empty(), properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme and . /// /// The authentication schemes to challenge. /// used to perform the authentication /// challenge. - internal ChallengeHttpResult(string authenticationScheme, AuthenticationProperties? properties) + internal Challenge(string authenticationScheme, AuthenticationProperties? properties) : this(new[] { authenticationScheme }, properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes and . /// /// The authentication scheme to challenge. /// used to perform the authentication /// challenge. - internal ChallengeHttpResult(IList authenticationSchemes, AuthenticationProperties? properties) + internal Challenge(IList authenticationSchemes, AuthenticationProperties? properties) { AuthenticationSchemes = authenticationSchemes.AsReadOnly(); Properties = properties; diff --git a/src/Http/Http.Results/src/Conflict.cs b/src/Http/Http.Results/src/Conflict.cs new file mode 100644 index 000000000000..00ce8edf25a1 --- /dev/null +++ b/src/Http/Http.Results/src/Conflict.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +/// +/// An that on execution will write an object to the response +/// with Conflict (409) status code. +/// +public sealed class Conflict : IResult +{ + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + internal Conflict() + { + } + + /// + /// Gets the HTTP status code. + /// + public int StatusCode => StatusCodes.Status409Conflict; + + /// + public Task ExecuteAsync(HttpContext httpContext) + { + // Creating the logger with a string to preserve the category after the refactoring. + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.ConflictObjectResult"); + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return Task.CompletedTask; + } +} diff --git a/src/Http/Http.Results/src/ConflictObjectHttpResult.cs b/src/Http/Http.Results/src/ConflictOfT.cs similarity index 76% rename from src/Http/Http.Results/src/ConflictObjectHttpResult.cs rename to src/Http/Http.Results/src/ConflictOfT.cs index 782775395bfc..bb65cde4b346 100644 --- a/src/Http/Http.Results/src/ConflictObjectHttpResult.cs +++ b/src/Http/Http.Results/src/ConflictOfT.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,14 +10,14 @@ namespace Microsoft.AspNetCore.Http; /// An that on execution will write an object to the response /// with Conflict (409) status code. /// -public sealed class ConflictObjectHttpResult : IResult +public sealed class Conflict : IResult { /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The error content to format in the entity body. - internal ConflictObjectHttpResult(object? error) + internal Conflict(TValue? error) { Value = error; HttpResultsHelper.ApplyProblemDetailsDefaultsIfNeeded(Value, StatusCode); @@ -26,7 +26,7 @@ internal ConflictObjectHttpResult(object? error) /// /// Gets the object result. /// - public object? Value { get; internal init; } + public TValue? Value { get; } /// /// Gets the HTTP status code. @@ -40,10 +40,12 @@ public Task ExecuteAsync(HttpContext httpContext) var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.ConflictObjectResult"); + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger: logger, - Value, - StatusCode); + Value); } } diff --git a/src/Http/Http.Results/src/ContentHttpResult.cs b/src/Http/Http.Results/src/Content.cs similarity index 75% rename from src/Http/Http.Results/src/ContentHttpResult.cs rename to src/Http/Http.Results/src/Content.cs index a50675408e2d..22f00c758e06 100644 --- a/src/Http/Http.Results/src/ContentHttpResult.cs +++ b/src/Http/Http.Results/src/Content.cs @@ -1,36 +1,36 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; /// -/// An that when executed +/// An that when executed /// will produce a response with content. /// -public sealed partial class ContentHttpResult : IResult +public sealed partial class Content : IResult { /// - /// Initializes a new instance of the class with the values. + /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. /// The Content-Type header for the response - internal ContentHttpResult(string? content, string? contentType) + internal Content(string? content, string? contentType) : this(content, contentType, statusCode: null) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// /// The value to format in the entity body. /// The HTTP status code of the response. /// The Content-Type header for the response - internal ContentHttpResult(string? content, string? contentType, int? statusCode) + internal Content(string? content, string? contentType, int? statusCode) { - Content = content; + ResponseContent = content; StatusCode = statusCode; ContentType = contentType; } @@ -38,7 +38,7 @@ internal ContentHttpResult(string? content, string? contentType, int? statusCode /// /// Gets or set the content representing the body of the response. /// - public string? Content { get; internal init; } + public string? ResponseContent { get; internal init; } /// /// Gets or sets the Content-Type header for the response. @@ -61,6 +61,6 @@ public Task ExecuteAsync(HttpContext httpContext) var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.ContentResult"); - return HttpResultsHelper.WriteResultAsContentAsync(httpContext, logger, Content, StatusCode, ContentType); + return HttpResultsHelper.WriteResultAsContentAsync(httpContext, logger, ResponseContent, StatusCode, ContentType); } } diff --git a/src/Http/Http.Results/src/Created.cs b/src/Http/Http.Results/src/Created.cs new file mode 100644 index 000000000000..a0e34db546eb --- /dev/null +++ b/src/Http/Http.Results/src/Created.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +/// +/// An that on execution will write an object to the response +/// with status code Created (201) and Location header. +/// +public sealed class Created : IResult +{ + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + /// The location at which the content has been created. + internal Created(string location) + { + Location = location; + } + + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + /// The location at which the content has been created. + /// The value to format in the entity body. + internal Created(Uri locationUri) + { + if (locationUri == null) + { + throw new ArgumentNullException(nameof(locationUri)); + } + + if (locationUri.IsAbsoluteUri) + { + Location = locationUri.AbsoluteUri; + } + else + { + Location = locationUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped); + } + } + + /// + /// Gets the HTTP status code. + /// + public int StatusCode => StatusCodes.Status201Created; + + /// + public string? Location { get; } + + /// + public Task ExecuteAsync(HttpContext httpContext) + { + // Creating the logger with a string to preserve the category after the refactoring. + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.CreatedResult"); + + if (!string.IsNullOrEmpty(Location)) + { + httpContext.Response.Headers.Location = Location; + } + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return Task.CompletedTask; + } +} diff --git a/src/Http/Http.Results/src/CreatedAtRoute.cs b/src/Http/Http.Results/src/CreatedAtRoute.cs new file mode 100644 index 000000000000..5cbe3e52988a --- /dev/null +++ b/src/Http/Http.Results/src/CreatedAtRoute.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +/// +/// An that on execution will write an object to the response +/// with status code Created (201) and Location header. +/// Targets a registered route. +/// +public sealed class CreatedAtRoute : IResult +{ + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + /// The route data to use for generating the URL. + internal CreatedAtRoute(object? routeValues) + : this(routeName: null, routeValues: routeValues) + { + } + + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + internal CreatedAtRoute( + string? routeName, + object? routeValues) + { + RouteName = routeName; + RouteValues = new RouteValueDictionary(routeValues); + } + + /// + /// Gets the name of the route to use for generating the URL. + /// + public string? RouteName { get; } + + /// + /// Gets the route data to use for generating the URL. + /// + public RouteValueDictionary? RouteValues { get; } + + /// + /// Gets the HTTP status code. + /// + public int StatusCode => StatusCodes.Status201Created; + + /// + public Task ExecuteAsync(HttpContext httpContext) + { + var linkGenerator = httpContext.RequestServices.GetRequiredService(); + var url = linkGenerator.GetUriByRouteValues( + httpContext, + RouteName, + RouteValues, + fragment: FragmentString.Empty); + + if (string.IsNullOrEmpty(url)) + { + throw new InvalidOperationException("No route matches the supplied values."); + } + + // Creating the logger with a string to preserve the category after the refactoring. + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.CreatedAtRouteResult"); + + httpContext.Response.Headers.Location = url; + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return Task.CompletedTask; + } +} diff --git a/src/Http/Http.Results/src/CreatedAtRouteHttpResult.cs b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs similarity index 86% rename from src/Http/Http.Results/src/CreatedAtRouteHttpResult.cs rename to src/Http/Http.Results/src/CreatedAtRouteOfT.cs index f59593be8505..b39a170b439b 100644 --- a/src/Http/Http.Results/src/CreatedAtRouteHttpResult.cs +++ b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; @@ -12,30 +12,30 @@ namespace Microsoft.AspNetCore.Http; /// with status code Created (201) and Location header. /// Targets a registered route. /// -public sealed class CreatedAtRouteHttpResult : IResult +public sealed class CreatedAtRoute : IResult { /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The route data to use for generating the URL. /// The value to format in the entity body. - internal CreatedAtRouteHttpResult(object? routeValues, object? value) + internal CreatedAtRoute(object? routeValues, TValue? value) : this(routeName: null, routeValues: routeValues, value: value) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The value to format in the entity body. - internal CreatedAtRouteHttpResult( + internal CreatedAtRoute( string? routeName, object? routeValues, - object? value) + TValue? value) { Value = value; RouteName = routeName; @@ -46,7 +46,7 @@ internal CreatedAtRouteHttpResult( /// /// Gets the object result. /// - public object? Value { get; } + public TValue? Value { get; } /// /// Gets the name of the route to use for generating the URL. @@ -83,10 +83,13 @@ public Task ExecuteAsync(HttpContext httpContext) var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.CreatedAtRouteResult"); httpContext.Response.Headers.Location = url; + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger, - Value, - StatusCode); + Value); } } diff --git a/src/Http/Http.Results/src/CreatedHttpResult.cs b/src/Http/Http.Results/src/CreatedOfT.cs similarity index 80% rename from src/Http/Http.Results/src/CreatedHttpResult.cs rename to src/Http/Http.Results/src/CreatedOfT.cs index 4106cacd7fec..b066bdc6d376 100644 --- a/src/Http/Http.Results/src/CreatedHttpResult.cs +++ b/src/Http/Http.Results/src/CreatedOfT.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,15 +10,15 @@ namespace Microsoft.AspNetCore.Http; /// An that on execution will write an object to the response /// with status code Created (201) and Location header. /// -public sealed class CreatedHttpResult : IResult +public sealed class Created : IResult { /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The location at which the content has been created. /// The value to format in the entity body. - internal CreatedHttpResult(string location, object? value) + internal Created(string location, TValue? value) { Value = value; Location = location; @@ -26,12 +26,12 @@ internal CreatedHttpResult(string location, object? value) } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The location at which the content has been created. /// The value to format in the entity body. - internal CreatedHttpResult(Uri locationUri, object? value) + internal Created(Uri locationUri, TValue? value) { Value = value; HttpResultsHelper.ApplyProblemDetailsDefaultsIfNeeded(Value, StatusCode); @@ -54,7 +54,7 @@ internal CreatedHttpResult(Uri locationUri, object? value) /// /// Gets the object result. /// - public object? Value { get; } + public TValue? Value { get; } /// /// Gets the HTTP status code. @@ -75,10 +75,13 @@ public Task ExecuteAsync(HttpContext httpContext) // Creating the logger with a string to preserve the category after the refactoring. var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.CreatedResult"); + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger, - Value, - StatusCode); + Value); } } diff --git a/src/Http/Http.Results/src/EmptyHttpResult.cs b/src/Http/Http.Results/src/Empty.cs similarity index 64% rename from src/Http/Http.Results/src/EmptyHttpResult.cs rename to src/Http/Http.Results/src/Empty.cs index 9e9b25c166dd..e4bbaf9080dc 100644 --- a/src/Http/Http.Results/src/EmptyHttpResult.cs +++ b/src/Http/Http.Results/src/Empty.cs @@ -1,22 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// Represents an that when executed will /// do nothing. /// -public sealed class EmptyHttpResult : IResult +public sealed class Empty : IResult { - private EmptyHttpResult() + private Empty() { } /// - /// Gets an instance of . + /// Gets an instance of . /// - public static EmptyHttpResult Instance { get; } = new(); + public static Empty Instance { get; } = new(); /// public Task ExecuteAsync(HttpContext httpContext) diff --git a/src/Http/Http.Results/src/FileContentHttpResult.cs b/src/Http/Http.Results/src/FileContent.cs similarity index 90% rename from src/Http/Http.Results/src/FileContentHttpResult.cs rename to src/Http/Http.Results/src/FileContent.cs index 56cd17d13944..d3f8a31677ab 100644 --- a/src/Http/Http.Results/src/FileContentHttpResult.cs +++ b/src/Http/Http.Results/src/FileContent.cs @@ -6,35 +6,35 @@ using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// Represents an that when executed will /// write a file from the content to the response. /// -public sealed partial class FileContentHttpResult : IResult +public sealed partial class FileContent : IResult { /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the /// provided . /// /// The bytes that represent the file contents. /// The Content-Type of the file. - internal FileContentHttpResult(ReadOnlyMemory fileContents, string? contentType) + internal FileContent(ReadOnlyMemory fileContents, string? contentType) : this(fileContents, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The bytes that represent the file contents. /// The Content-Type header of the response. /// The suggested file name. - internal FileContentHttpResult( + internal FileContent( ReadOnlyMemory fileContents, string? contentType, string? fileDownloadName) @@ -43,7 +43,7 @@ internal FileContentHttpResult( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The bytes that represent the file contents. /// The Content-Type of the file. @@ -51,7 +51,7 @@ internal FileContentHttpResult( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal FileContentHttpResult( + internal FileContent( ReadOnlyMemory fileContents, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/src/ForbidHttpResult.cs b/src/Http/Http.Results/src/Forbid.cs similarity index 80% rename from src/Http/Http.Results/src/ForbidHttpResult.cs rename to src/Http/Http.Results/src/Forbid.cs index f9d8d9c27897..d76be06654ba 100644 --- a/src/Http/Http.Results/src/ForbidHttpResult.cs +++ b/src/Http/Http.Results/src/Forbid.cs @@ -6,72 +6,72 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that on execution invokes . /// -public sealed partial class ForbidHttpResult : IResult +public sealed partial class Forbid : IResult { /// - /// Initializes a new instance of . + /// Initializes a new instance of . /// - internal ForbidHttpResult() + internal Forbid() : this(Array.Empty()) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme. /// /// The authentication scheme to challenge. - internal ForbidHttpResult(string authenticationScheme) + internal Forbid(string authenticationScheme) : this(new[] { authenticationScheme }) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes. /// /// The authentication schemes to challenge. - internal ForbidHttpResult(IList authenticationSchemes) + internal Forbid(IList authenticationSchemes) : this(authenticationSchemes, properties: null) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified . /// /// used to perform the authentication /// challenge. - internal ForbidHttpResult(AuthenticationProperties? properties) + internal Forbid(AuthenticationProperties? properties) : this(Array.Empty(), properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme and . /// /// The authentication schemes to challenge. /// used to perform the authentication /// challenge. - internal ForbidHttpResult(string authenticationScheme, AuthenticationProperties? properties) + internal Forbid(string authenticationScheme, AuthenticationProperties? properties) : this(new[] { authenticationScheme }, properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes and . /// /// The authentication scheme to challenge. /// used to perform the authentication /// challenge. - internal ForbidHttpResult(IList authenticationSchemes, AuthenticationProperties? properties) + internal Forbid(IList authenticationSchemes, AuthenticationProperties? properties) { AuthenticationSchemes = authenticationSchemes.AsReadOnly(); Properties = properties; diff --git a/src/Http/Http.Results/src/FileStreamHttpResult.cs b/src/Http/Http.Results/src/HttpFileStream.cs similarity index 91% rename from src/Http/Http.Results/src/FileStreamHttpResult.cs rename to src/Http/Http.Results/src/HttpFileStream.cs index 4a2273c535f0..c349f785d901 100644 --- a/src/Http/Http.Results/src/FileStreamHttpResult.cs +++ b/src/Http/Http.Results/src/HttpFileStream.cs @@ -6,35 +6,35 @@ using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// Represents an that when executed will /// write a file from a stream to the response. /// -public sealed class FileStreamHttpResult : IResult +public sealed class HttpFileStream : IResult { /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the /// provided . /// /// The stream with the file. /// The Content-Type of the file. - internal FileStreamHttpResult(Stream fileStream, string? contentType) + internal HttpFileStream(Stream fileStream, string? contentType) : this(fileStream, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The stream with the file. /// The Content-Type header of the response. /// The suggested file name. - internal FileStreamHttpResult( + internal HttpFileStream( Stream fileStream, string? contentType, string? fileDownloadName) @@ -43,7 +43,7 @@ internal FileStreamHttpResult( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The stream with the file. /// The Content-Type of the file. @@ -51,7 +51,7 @@ internal FileStreamHttpResult( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal FileStreamHttpResult( + internal HttpFileStream( Stream fileStream, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/src/HttpResultsHelper.cs b/src/Http/Http.Results/src/HttpResultsHelper.cs index f447e1d9539e..361f1f093fd0 100644 --- a/src/Http/Http.Results/src/HttpResultsHelper.cs +++ b/src/Http/Http.Results/src/HttpResultsHelper.cs @@ -10,25 +10,25 @@ using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Http; + internal static partial class HttpResultsHelper { private const string DefaultContentType = "text/plain; charset=utf-8"; private static readonly Encoding DefaultEncoding = Encoding.UTF8; - public static Task WriteResultAsJsonAsync( + public static Task WriteResultAsJsonAsync( HttpContext httpContext, ILogger logger, - object? value, - int? statusCode, + T? value, string? contentType = null, JsonSerializerOptions? jsonSerializerOptions = null) { - Log.WritingResultAsJson(logger, value, statusCode); + //Log.WritingResultAsJson(logger, value, statusCode); - if (statusCode is { } code) - { - httpContext.Response.StatusCode = code; - } + //if (statusCode is { } code) + //{ + // httpContext.Response.StatusCode = code; + //} if (value is null) { diff --git a/src/Http/Http.Results/src/JsonHttpResult.cs b/src/Http/Http.Results/src/Json.cs similarity index 74% rename from src/Http/Http.Results/src/JsonHttpResult.cs rename to src/Http/Http.Results/src/Json.cs index 1e7800a32bdb..98e6ac13b6fd 100644 --- a/src/Http/Http.Results/src/JsonHttpResult.cs +++ b/src/Http/Http.Results/src/Json.cs @@ -5,54 +5,54 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An action result which formats the given object as JSON. /// -public sealed class JsonHttpResult : IResult +public sealed partial class Json : IResult { /// - /// Initializes a new instance of the class with the values. + /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. /// The serializer settings. - internal JsonHttpResult(object? value, JsonSerializerOptions? jsonSerializerOptions) + internal Json(TValue? value, JsonSerializerOptions? jsonSerializerOptions) : this(value, statusCode: null, contentType: null, jsonSerializerOptions: jsonSerializerOptions) { } /// - /// Initializes a new instance of the class with the values. + /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. /// The HTTP status code of the response. /// The serializer settings. - internal JsonHttpResult(object? value, int? statusCode, JsonSerializerOptions? jsonSerializerOptions) + internal Json(TValue? value, int? statusCode, JsonSerializerOptions? jsonSerializerOptions) : this(value, statusCode: statusCode, contentType: null, jsonSerializerOptions: jsonSerializerOptions) { } /// - /// Initializes a new instance of the class with the values. + /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. /// The value for the Content-Type header /// The serializer settings. - internal JsonHttpResult(object? value, string? contentType, JsonSerializerOptions? jsonSerializerOptions) + internal Json(TValue? value, string? contentType, JsonSerializerOptions? jsonSerializerOptions) : this(value, statusCode: null, contentType: contentType, jsonSerializerOptions: jsonSerializerOptions) { } /// - /// Initializes a new instance of the class with the values. + /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. /// The HTTP status code of the response. /// The serializer settings. /// The value for the Content-Type header - internal JsonHttpResult(object? value, int? statusCode, string? contentType, JsonSerializerOptions? jsonSerializerOptions) + internal Json(TValue? value, int? statusCode, string? contentType, JsonSerializerOptions? jsonSerializerOptions) { Value = value; StatusCode = statusCode; @@ -69,7 +69,7 @@ internal JsonHttpResult(object? value, int? statusCode, string? contentType, Jso /// /// Gets the object result. /// - public object? Value { get; } + public TValue? Value { get; } /// /// Gets the value for the Content-Type header. @@ -88,11 +88,16 @@ public Task ExecuteAsync(HttpContext httpContext) var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.JsonResult"); + if (StatusCode is { } code) + { + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, code); + httpContext.Response.StatusCode = code; + } + return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger, Value, - StatusCode, ContentType, JsonSerializerOptions); } diff --git a/src/Http/Http.Results/src/NoContentHttpResult.cs b/src/Http/Http.Results/src/NoContent.cs similarity index 84% rename from src/Http/Http.Results/src/NoContentHttpResult.cs rename to src/Http/Http.Results/src/NoContent.cs index 0339cc3f1f38..7c63adcbf6da 100644 --- a/src/Http/Http.Results/src/NoContentHttpResult.cs +++ b/src/Http/Http.Results/src/NoContent.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,12 +10,12 @@ namespace Microsoft.AspNetCore.Http; /// Represents an that when executed will /// produce an HTTP response with the No Content (204) status code. /// -public class NoContentHttpResult : IResult +public class NoContent : IResult { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - internal NoContentHttpResult() + internal NoContent() { } diff --git a/src/Http/Http.Results/src/NotFound.cs b/src/Http/Http.Results/src/NotFound.cs new file mode 100644 index 000000000000..bc20b318e9ab --- /dev/null +++ b/src/Http/Http.Results/src/NotFound.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +/// +/// An that on execution will write an object to the response +/// with Not Found (404) status code. +/// +public sealed class NotFound : IResult +{ + /// + /// Initializes a new instance of the class with the values. + /// + internal NotFound() + { + } + + /// + /// Gets the HTTP status code. + /// + public int StatusCode => StatusCodes.Status404NotFound; + + /// + public Task ExecuteAsync(HttpContext httpContext) + { + // Creating the logger with a string to preserve the category after the refactoring. + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.NotFoundObjectResult"); + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return Task.CompletedTask; + } +} diff --git a/src/Http/Http.Results/src/NotFoundObjectHttpResult.cs b/src/Http/Http.Results/src/NotFoundOfT.cs similarity index 75% rename from src/Http/Http.Results/src/NotFoundObjectHttpResult.cs rename to src/Http/Http.Results/src/NotFoundOfT.cs index 45220b7d0483..d61fab157a68 100644 --- a/src/Http/Http.Results/src/NotFoundObjectHttpResult.cs +++ b/src/Http/Http.Results/src/NotFoundOfT.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,13 +10,13 @@ namespace Microsoft.AspNetCore.Http; /// An that on execution will write an object to the response /// with Not Found (404) status code. /// -public sealed class NotFoundObjectHttpResult : IResult +public sealed class NotFound : IResult { /// - /// Initializes a new instance of the class with the values. + /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. - internal NotFoundObjectHttpResult(object? value) + internal NotFound(TValue? value) { Value = value; HttpResultsHelper.ApplyProblemDetailsDefaultsIfNeeded(Value, StatusCode); @@ -25,7 +25,7 @@ internal NotFoundObjectHttpResult(object? value) /// /// Gets the object result. /// - public object? Value { get; internal init; } + public TValue? Value { get; internal init; } /// /// Gets the HTTP status code. @@ -39,10 +39,12 @@ public Task ExecuteAsync(HttpContext httpContext) var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.NotFoundObjectResult"); + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger: logger, - Value, - StatusCode); + Value); } } diff --git a/src/Http/Http.Results/src/ObjectHttpResult.cs b/src/Http/Http.Results/src/ObjectHttpResult.cs deleted file mode 100644 index 252ab122a1da..000000000000 --- a/src/Http/Http.Results/src/ObjectHttpResult.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.AspNetCore.Http; - -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -/// -/// An that on execution will write an object to the response. -/// -internal sealed class ObjectHttpResult : IResult -{ - /// - /// Creates a new instance - /// with the provided . - /// - internal ObjectHttpResult(object? value) - : this(value, null) - { - } - - /// - /// Creates a new instance with the provided - /// , . - /// - internal ObjectHttpResult(object? value, int? statusCode) - : this(value, statusCode, contentType: null) - { - } - - /// - /// Creates a new instance with the provided - /// , and . - /// - internal ObjectHttpResult(object? value, int? statusCode, string? contentType) - { - Value = value; - - if (value is ProblemDetails problemDetails) - { - HttpResultsHelper.ApplyProblemDetailsDefaults(problemDetails, statusCode); - statusCode ??= problemDetails.Status; - } - - StatusCode = statusCode; - ContentType = contentType; - } - - /// - /// Gets the object result. - /// - public object? Value { get; internal init; } - - /// - /// Gets or sets the value for the Content-Type header. - /// - public string? ContentType { get; internal init; } - - /// - /// Gets the HTTP status code. - /// - public int? StatusCode { get; internal init; } - - /// - public Task ExecuteAsync(HttpContext httpContext) - { - // Creating the logger with a string to preserve the category after the refactoring. - var loggerFactory = httpContext.RequestServices.GetRequiredService(); - var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.ObjectResult"); - - return HttpResultsHelper.WriteResultAsJsonAsync( - httpContext, - logger: logger, - Value, - StatusCode, - ContentType); - } -} diff --git a/src/Http/Http.Results/src/Ok.cs b/src/Http/Http.Results/src/Ok.cs new file mode 100644 index 000000000000..0c9e51bd240c --- /dev/null +++ b/src/Http/Http.Results/src/Ok.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +/// +/// An that on execution will write an object to the response +/// with Ok (200) status code. +/// +public sealed class Ok : IResult +{ + /// + /// Initializes a new instance of the class with the values. + /// + /// The value to format in the entity body. + internal Ok() + { + } + + /// + /// Gets the HTTP status code. + /// + public int StatusCode => StatusCodes.Status200OK; + + /// + public Task ExecuteAsync(HttpContext httpContext) + { + // Creating the logger with a string to preserve the category after the refactoring. + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.OkObjectResult"); + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return Task.CompletedTask; + } +} diff --git a/src/Http/Http.Results/src/OkObjectHttpResult.cs b/src/Http/Http.Results/src/OkOfT.cs similarity index 77% rename from src/Http/Http.Results/src/OkObjectHttpResult.cs rename to src/Http/Http.Results/src/OkOfT.cs index 2dedc139d7ab..2f25487a9b24 100644 --- a/src/Http/Http.Results/src/OkObjectHttpResult.cs +++ b/src/Http/Http.Results/src/OkOfT.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -11,13 +11,13 @@ namespace Microsoft.AspNetCore.Http; /// An that on execution will write an object to the response /// with Ok (200) status code. /// -public sealed class OkObjectHttpResult : IResult +public sealed class Ok : IResult { /// - /// Initializes a new instance of the class with the values. + /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. - internal OkObjectHttpResult(object? value) + internal Ok(TValue? value) { Value = value; HttpResultsHelper.ApplyProblemDetailsDefaultsIfNeeded(Value, StatusCode); @@ -26,7 +26,7 @@ internal OkObjectHttpResult(object? value) /// /// Gets the object result. /// - public object? Value { get; internal init; } + public TValue? Value { get; } /// /// Gets the HTTP status code. @@ -40,10 +40,12 @@ public Task ExecuteAsync(HttpContext httpContext) var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.OkObjectResult"); + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger: logger, - Value, - StatusCode); + Value); } } diff --git a/src/Http/Http.Results/src/PhysicalFileHttpResult.cs b/src/Http/Http.Results/src/PhysicalFile.cs similarity index 91% rename from src/Http/Http.Results/src/PhysicalFileHttpResult.cs rename to src/Http/Http.Results/src/PhysicalFile.cs index 97f8e01dca38..ecbff3d8c46f 100644 --- a/src/Http/Http.Results/src/PhysicalFileHttpResult.cs +++ b/src/Http/Http.Results/src/PhysicalFile.cs @@ -5,34 +5,34 @@ using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// -/// A on execution will write a file from disk to the response +/// A on execution will write a file from disk to the response /// using mechanisms provided by the host. /// -public sealed partial class PhysicalFileHttpResult : IResult +public sealed partial class PhysicalFile : IResult { /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. - internal PhysicalFileHttpResult(string fileName, string? contentType) + internal PhysicalFile(string fileName, string? contentType) : this(fileName, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. /// The suggested file name. - internal PhysicalFileHttpResult( + internal PhysicalFile( string fileName, string? contentType, string? fileDownloadName) @@ -41,7 +41,7 @@ internal PhysicalFileHttpResult( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. @@ -49,7 +49,7 @@ internal PhysicalFileHttpResult( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal PhysicalFileHttpResult( + internal PhysicalFile( string fileName, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/src/ProblemHttpResult.cs b/src/Http/Http.Results/src/Problem.cs similarity index 77% rename from src/Http/Http.Results/src/ProblemHttpResult.cs rename to src/Http/Http.Results/src/Problem.cs index 0a5c52a0fcca..6c03fd599169 100644 --- a/src/Http/Http.Results/src/ProblemHttpResult.cs +++ b/src/Http/Http.Results/src/Problem.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; @@ -11,14 +11,14 @@ namespace Microsoft.AspNetCore.Http; /// An that on execution will write Problem Details /// HTTP API responses based on https://tools.ietf.org/html/rfc7807 /// -public sealed class ProblemHttpResult : IResult +public sealed class Problem : IResult { /// - /// Creates a new instance with + /// Creates a new instance with /// the provided . /// /// The instance to format in the entity body. - internal ProblemHttpResult(ProblemDetails problemDetails) + internal Problem(ProblemDetails problemDetails) { ProblemDetails = problemDetails; HttpResultsHelper.ApplyProblemDetailsDefaults(ProblemDetails, statusCode: null); @@ -43,13 +43,18 @@ internal ProblemHttpResult(ProblemDetails problemDetails) public Task ExecuteAsync(HttpContext httpContext) { var loggerFactory = httpContext.RequestServices.GetRequiredService(); - var logger = loggerFactory.CreateLogger(typeof(ProblemHttpResult)); + var logger = loggerFactory.CreateLogger(typeof(Problem)); + + if (StatusCode is { } code) + { + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, code); + httpContext.Response.StatusCode = code; + } return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger, value: ProblemDetails, - StatusCode, ContentType); } } diff --git a/src/Http/Http.Results/src/PushStreamHttpResult.cs b/src/Http/Http.Results/src/PushStream.cs similarity index 90% rename from src/Http/Http.Results/src/PushStreamHttpResult.cs rename to src/Http/Http.Results/src/PushStream.cs index 71f454af2bf2..d7bac2daf7fc 100644 --- a/src/Http/Http.Results/src/PushStreamHttpResult.cs +++ b/src/Http/Http.Results/src/PushStream.cs @@ -5,36 +5,36 @@ using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// Represents an that when executed will /// write a file from the writer callback to the response. /// -public sealed class PushStreamHttpResult : IResult +public sealed class PushStream : IResult { private readonly Func _streamWriterCallback; /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the provided . /// /// The stream writer callback. /// The Content-Type header of the response. - internal PushStreamHttpResult(Func streamWriterCallback, string? contentType) + internal PushStream(Func streamWriterCallback, string? contentType) : this(streamWriterCallback, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The stream writer callback. /// The Content-Type header of the response. /// The suggested file name. - internal PushStreamHttpResult( + internal PushStream( Func streamWriterCallback, string? contentType, string? fileDownloadName) @@ -43,7 +43,7 @@ internal PushStreamHttpResult( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The stream writer callback. /// The Content-Type header of the response. @@ -51,7 +51,7 @@ internal PushStreamHttpResult( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal PushStreamHttpResult( + internal PushStream( Func streamWriterCallback, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/src/RedirectHttpResult.cs b/src/Http/Http.Results/src/Redirect.cs similarity index 85% rename from src/Http/Http.Results/src/RedirectHttpResult.cs rename to src/Http/Http.Results/src/Redirect.cs index 3c1bdc6ce911..510d12937f51 100644 --- a/src/Http/Http.Results/src/RedirectHttpResult.cs +++ b/src/Http/Http.Results/src/Redirect.cs @@ -5,49 +5,49 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), /// or Permanent Redirect (308) response with a Location header to the supplied URL. /// -public sealed partial class RedirectHttpResult : IResult +public sealed partial class Redirect : IResult { /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The URL to redirect to. - internal RedirectHttpResult(string url) + internal Redirect(string url) : this(url, permanent: false) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The URL to redirect to. /// Specifies whether the redirect should be permanent (301) or temporary (302). - internal RedirectHttpResult(string url, bool permanent) + internal Redirect(string url, bool permanent) : this(url, permanent, preserveMethod: false) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The URL to redirect to. /// Specifies whether the redirect should be permanent (301) or temporary (302). /// If set to true, make the temporary redirect (307) /// or permanent redirect (308) preserve the initial request method. - internal RedirectHttpResult(string url, bool permanent, bool preserveMethod) + internal Redirect(string url, bool permanent, bool preserveMethod) : this(url, acceptLocalUrlOnly: false, permanent, preserveMethod) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The URL to redirect to. @@ -56,7 +56,7 @@ internal RedirectHttpResult(string url, bool permanent, bool preserveMethod) /// or permanent redirect (308) preserve the initial request method. /// If set to true, only local URLs are accepted /// and will throw an exception when the supplied URL is not considered local. - internal RedirectHttpResult(string url, bool acceptLocalUrlOnly, bool permanent, bool preserveMethod) + internal Redirect(string url, bool acceptLocalUrlOnly, bool permanent, bool preserveMethod) { if (url == null) { diff --git a/src/Http/Http.Results/src/RedirectToRouteHttpResult.cs b/src/Http/Http.Results/src/RedirectToRoute.cs similarity index 91% rename from src/Http/Http.Results/src/RedirectToRouteHttpResult.cs rename to src/Http/Http.Results/src/RedirectToRoute.cs index 586694792e59..af3ec08cc004 100644 --- a/src/Http/Http.Results/src/RedirectToRouteHttpResult.cs +++ b/src/Http/Http.Results/src/RedirectToRoute.cs @@ -5,32 +5,32 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), /// or Permanent Redirect (308) response with a Location header. /// Targets a registered route. /// -public sealed partial class RedirectToRouteHttpResult : IResult +public sealed partial class RedirectToRoute : IResult { /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The parameters for the route. - internal RedirectToRouteHttpResult(object? routeValues) + internal RedirectToRoute(object? routeValues) : this(routeName: null, routeValues: routeValues) { } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. /// The parameters for the route. - internal RedirectToRouteHttpResult( + internal RedirectToRoute( string? routeName, object? routeValues) : this(routeName, routeValues, permanent: false) @@ -38,14 +38,14 @@ internal RedirectToRouteHttpResult( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. /// The parameters for the route. /// If set to true, makes the redirect permanent (301). /// Otherwise a temporary redirect is used (302). - internal RedirectToRouteHttpResult( + internal RedirectToRoute( string? routeName, object? routeValues, bool permanent) @@ -54,7 +54,7 @@ internal RedirectToRouteHttpResult( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. @@ -63,7 +63,7 @@ internal RedirectToRouteHttpResult( /// Otherwise a temporary redirect is used (302). /// If set to true, make the temporary redirect (307) /// or permanent redirect (308) preserve the initial request method. - internal RedirectToRouteHttpResult( + internal RedirectToRoute( string? routeName, object? routeValues, bool permanent, @@ -73,13 +73,13 @@ internal RedirectToRouteHttpResult( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. /// The parameters for the route. /// The fragment to add to the URL. - internal RedirectToRouteHttpResult( + internal RedirectToRoute( string? routeName, object? routeValues, string? fragment) @@ -88,7 +88,7 @@ internal RedirectToRouteHttpResult( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. @@ -96,7 +96,7 @@ internal RedirectToRouteHttpResult( /// If set to true, makes the redirect permanent (301). /// Otherwise a temporary redirect is used (302). /// The fragment to add to the URL. - internal RedirectToRouteHttpResult( + internal RedirectToRoute( string? routeName, object? routeValues, bool permanent, @@ -106,7 +106,7 @@ internal RedirectToRouteHttpResult( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. @@ -116,7 +116,7 @@ internal RedirectToRouteHttpResult( /// If set to true, make the temporary redirect (307) /// or permanent redirect (308) preserve the initial request method. /// The fragment to add to the URL. - internal RedirectToRouteHttpResult( + internal RedirectToRoute( string? routeName, object? routeValues, bool permanent, diff --git a/src/Http/Http.Results/src/Results.Typed.cs b/src/Http/Http.Results/src/Results.Typed.cs new file mode 100644 index 000000000000..00dc7072d8db --- /dev/null +++ b/src/Http/Http.Results/src/Results.Typed.cs @@ -0,0 +1,852 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO.Pipelines; +using System.Security.Claims; +using System.Text; +using System.Text.Json; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Http; + +/// +/// A factory for . +/// +public static partial class Results +{ + public static class Typed + { + /// + /// Creates an that on execution invokes . + /// + /// The behavior of this method depends on the in use. + /// and + /// are among likely status results. + /// + /// + /// used to perform the authentication + /// challenge. + /// The authentication schemes to challenge. + /// The created for the response. + public static Challenge Challenge( + AuthenticationProperties? properties = null, + IList? authenticationSchemes = null) + => new(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + + /// + /// Creates a that on execution invokes . + /// + /// By default, executing this result returns a . Some authentication schemes, such as cookies, + /// will convert to a redirect to show a login page. + /// + /// + /// used to perform the authentication + /// challenge. + /// The authentication schemes to challenge. + /// The created for the response. + /// + /// Some authentication schemes, such as cookies, will convert to + /// a redirect to show a login page. + /// + public static Forbid Forbid(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) + => new(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + + /// + /// Creates an that on execution invokes . + /// + /// The containing the user claims. + /// used to perform the sign-in operation. + /// The authentication scheme to use for the sign-in operation. + /// The created for the response. + public static SignIn SignIn( + ClaimsPrincipal principal, + AuthenticationProperties? properties = null, + string? authenticationScheme = null) + => new(principal, authenticationScheme, properties); + + /// + /// Creates an that on execution invokes . + /// + /// used to perform the sign-out operation. + /// The authentication scheme to use for the sign-out operation. + /// The created for the response. + public static SignOut SignOut(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) + => new(authenticationSchemes ?? Array.Empty(), properties); + + /// + /// Writes the string to the HTTP response. + /// + /// This is an alias for . + /// + /// + /// The content to write to the response. + /// The content type (MIME type). + /// The content encoding. + /// The created object for the response. + /// + /// If encoding is provided by both the 'charset' and the parameters, then + /// the parameter is chosen as the final encoding. + /// + public static Content Content(string content, string? contentType = null, Encoding? contentEncoding = null) + => Text(content, contentType, contentEncoding); + + /// + /// Writes the string to the HTTP response. + /// + /// This is an alias for . + /// + /// + /// The content to write to the response. + /// The content type (MIME type). + /// The content encoding. + /// The created object for the response. + /// + /// If encoding is provided by both the 'charset' and the parameters, then + /// the parameter is chosen as the final encoding. + /// + public static Content Text(string content, string? contentType = null, Encoding? contentEncoding = null) + { + MediaTypeHeaderValue? mediaTypeHeaderValue = null; + if (contentType is not null) + { + mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType); + mediaTypeHeaderValue.Encoding = contentEncoding ?? mediaTypeHeaderValue.Encoding; + } + + return new(content, mediaTypeHeaderValue?.ToString()); + } + + /// + /// Writes the string to the HTTP response. + /// + /// The content to write to the response. + /// The content type (MIME type). + /// The created object for the response. + public static Content Content(string content, MediaTypeHeaderValue contentType) + => new(content, contentType.ToString()); + + /// + /// Creates a that serializes the specified object to JSON. + /// + /// The object to write as JSON. + /// The serializer options to use when serializing the value. + /// The content-type to set on the response. + /// The status code to set on the response. + /// The created that serializes the specified + /// as JSON format for the response. + /// Callers should cache an instance of serializer settings to avoid + /// recreating cached data with each call. + public static Json Json(TValue? data, JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) + => new(data, statusCode, options) + { + ContentType = contentType, + }; + + /// + /// Writes the byte-array content to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// This API is an alias for . + /// + /// The file contents. + /// The Content-Type of the file. + /// The suggested file name. + /// Set to true to enable range requests processing. + /// The of when the file was last modified. + /// The associated with the file. + /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static FileContent File( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + byte[] fileContents, + string? contentType = null, + string? fileDownloadName = null, + bool enableRangeProcessing = false, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null) + => new(fileContents, contentType) + { + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + LastModified = lastModified, + EntityTag = entityTag, + }; + + /// + /// Writes the byte-array content to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// This API is an alias for . + /// + /// The file contents. + /// The Content-Type of the file. + /// The suggested file name. + /// Set to true to enable range requests processing. + /// The of when the file was last modified. + /// The associated with the file. + /// The created for the response. + public static FileContent Bytes( + byte[] contents, + string? contentType = null, + string? fileDownloadName = null, + bool enableRangeProcessing = false, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null) + => new(contents, contentType) + { + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + LastModified = lastModified, + EntityTag = entityTag, + }; + + /// + /// Writes the byte-array content to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The file contents. + /// The Content-Type of the file. + /// The suggested file name. + /// Set to true to enable range requests processing. + /// The of when the file was last modified. + /// The associated with the file. + /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static FileContent Bytes( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + ReadOnlyMemory contents, + string? contentType = null, + string? fileDownloadName = null, + bool enableRangeProcessing = false, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null) + => new(contents, contentType) + { + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + LastModified = lastModified, + EntityTag = entityTag, + }; + + /// + /// Writes the specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// This API is an alias for . + /// + /// + /// The with the contents of the file. + /// The Content-Type of the file. + /// The the file name to be used in the Content-Disposition header. + /// The of when the file was last modified. + /// Used to configure the Last-Modified response header and perform conditional range requests. + /// The to be configure the ETag response header + /// and perform conditional requests. + /// Set to true to enable range requests processing. + /// The created for the response. + /// + /// The parameter is disposed after the response is sent. + /// +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static HttpFileStream File( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + Stream fileStream, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(fileStream, contentType) + { + LastModified = lastModified, + EntityTag = entityTag, + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + }; + } + + /// + /// Writes the specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// This API is an alias for . + /// + /// + /// The to write to the response. + /// The Content-Type of the response. Defaults to application/octet-stream. + /// The the file name to be used in the Content-Disposition header. + /// The of when the file was last modified. + /// Used to configure the Last-Modified response header and perform conditional range requests. + /// The to be configure the ETag response header + /// and perform conditional requests. + /// Set to true to enable range requests processing. + /// The created for the response. + /// + /// The parameter is disposed after the response is sent. + /// + public static HttpFileStream Stream( + Stream stream, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(stream, contentType) + { + LastModified = lastModified, + EntityTag = entityTag, + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + }; + } + + /// + /// Writes the contents of specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The to write to the response. + /// The Content-Type of the response. Defaults to application/octet-stream. + /// The the file name to be used in the Content-Disposition header. + /// The of when the file was last modified. + /// Used to configure the Last-Modified response header and perform conditional range requests. + /// The to be configure the ETag response header + /// and perform conditional requests. + /// Set to true to enable range requests processing. + /// The created for the response. + /// + /// The parameter is completed after the response is sent. + /// +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static HttpFileStream Stream( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + PipeReader pipeReader, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(pipeReader.AsStream(), contentType) + { + LastModified = lastModified, + EntityTag = entityTag, + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + }; + } + + /// + /// Allows writing directly to the response body. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The callback that allows users to write directly to the response body. + /// The Content-Type of the response. Defaults to application/octet-stream. + /// The the file name to be used in the Content-Disposition header. + /// The of when the file was last modified. + /// Used to configure the Last-Modified response header and perform conditional range requests. + /// The to be configure the ETag response header + /// and perform conditional requests. + /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static PushStream Stream( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + Func streamWriterCallback, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null) + { + return new(streamWriterCallback, contentType) + { + LastModified = lastModified, + EntityTag = entityTag, + FileDownloadName = fileDownloadName, + }; + } + + /// + /// Writes the file at the specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The path to the file. When not rooted, resolves the path relative to . + /// The Content-Type of the file. + /// The suggested file name. + /// The of when the file was last modified. + /// The associated with the file. + /// Set to true to enable range requests processing. + /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static PhysicalFile PhysicalFile( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + string path, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(path, contentType) + { + FileDownloadName = fileDownloadName, + LastModified = lastModified, + EntityTag = entityTag, + EnableRangeProcessing = enableRangeProcessing, + }; + } + + /// + /// Writes the file at the specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The path to the file. When not rooted, resolves the path relative to . + /// The Content-Type of the file. + /// The suggested file name. + /// The of when the file was last modified. + /// The associated with the file. + /// Set to true to enable range requests processing. + /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters + public static VirtualFile VirtualFile( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters + string path, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(path, contentType) + { + FileDownloadName = fileDownloadName, + LastModified = lastModified, + EntityTag = entityTag, + EnableRangeProcessing = enableRangeProcessing, + }; + } + + /// + /// Redirects to the specified . + /// + /// When and are set, sets the status code. + /// When is set, sets the status code. + /// When is set, sets the status code. + /// Otherwise, configures . + /// + /// + /// The URL to redirect to. + /// Specifies whether the redirect should be permanent (301) or temporary (302). + /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. + /// The created for the response. + public static Redirect Redirect(string url, bool permanent = false, bool preserveMethod = false) + => new(url, permanent, preserveMethod); + + /// + /// Redirects to the specified . + /// + /// When and are set, sets the status code. + /// When is set, sets the status code. + /// When is set, sets the status code. + /// Otherwise, configures . + /// + /// + /// The local URL to redirect to. + /// Specifies whether the redirect should be permanent (301) or temporary (302). + /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. + /// The created for the response. + public static Redirect LocalRedirect(string localUrl, bool permanent = false, bool preserveMethod = false) + => new(localUrl, acceptLocalUrlOnly: true, permanent, preserveMethod); + + /// + /// Redirects to the specified route. + /// + /// When and are set, sets the status code. + /// When is set, sets the status code. + /// When is set, sets the status code. + /// Otherwise, configures . + /// + /// + /// The name of the route. + /// The parameters for a route. + /// Specifies whether the redirect should be permanent (301) or temporary (302). + /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. + /// The fragment to add to the URL. + /// The created for the response. + public static RedirectToRoute RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) + => new( + routeName: routeName, + routeValues: routeValues, + permanent: permanent, + preserveMethod: preserveMethod, + fragment: fragment); + + /// + /// Creates a object by specifying a . + /// + /// The status code to set on the response. + /// The created object for the response. + public static Status StatusCode(int statusCode) + => new(statusCode); + + /// + /// Produces a response. + /// + /// The created for the response. + public static NotFound NotFound() => new(); + + /// + /// Produces a response. + /// + /// The value to be included in the HTTP response body. + /// The created for the response. + public static NotFound NotFound(TValue? value) => new(value); + + /// + /// Produces a response. + /// + /// The created for the response. + public static Unauthorized Unauthorized() => new(); + + /// + /// Produces a response. + /// + /// The created for the response. + public static BadRequest BadRequest() => new(); + + /// + /// Produces a response. + /// + /// The value to be included in the HTTP response body. + /// The created for the response. + public static BadRequest BadRequest(TValue? error) => new(error); + + /// + /// Produces a response. + /// + /// The created for the response. + public static Conflict Conflict() => new(); + + /// + /// Produces a response. + /// + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Conflict Conflict(TValue? error) => new(error); + + /// + /// Produces a response. + /// + /// The created for the response. + public static NoContent NoContent() => new(); + + /// + /// Produces a response. + /// + /// The created for the response. + public static Ok Ok() => new(); + + /// + /// Produces a response. + /// + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Ok Ok(TValue? value) => new(value); + + /// + /// Produces a response. + /// + /// The created for the response. + public static UnprocessableEntity UnprocessableEntity() => new(); + + /// + /// Produces a response. + /// + /// The value to be included in the HTTP response body. + /// The created for the response. + public static UnprocessableEntity UnprocessableEntity(TValue? error) => new(error); + + /// + /// Produces a response. + /// + /// The value for . + /// The value for . + /// The value for . + /// The value for . + /// The value for . + /// The value for . + /// The created for the response. + public static Problem Problem( + string? detail = null, + string? instance = null, + int? statusCode = null, + string? title = null, + string? type = null, + IDictionary? extensions = null) + { + var problemDetails = new ProblemDetails + { + Detail = detail, + Instance = instance, + Status = statusCode, + Title = title, + Type = type, + }; + + if (extensions is not null) + { + foreach (var extension in extensions) + { + problemDetails.Extensions.Add(extension); + } + } + + return new Problem(problemDetails); + } + + /// + /// Produces a response. + /// + /// The object to produce a response from. + /// The created for the response. + public static Problem Problem(ProblemDetails problemDetails) + { + return new Problem(problemDetails); + } + + /// + /// Produces a response + /// with a value. + /// + /// One or more validation errors. + /// The value for . + /// The value for . + /// The status code. + /// The value for . Defaults to "One or more validation errors occurred." + /// The value for . + /// The value for . + /// The created for the response. + public static Problem ValidationProblem( + IDictionary errors, + string? detail = null, + string? instance = null, + int? statusCode = null, + string? title = null, + string? type = null, + IDictionary? extensions = null) + { + var problemDetails = new HttpValidationProblemDetails(errors) + { + Detail = detail, + Instance = instance, + Type = type, + Status = statusCode, + }; + + problemDetails.Title = title ?? problemDetails.Title; + + if (extensions is not null) + { + foreach (var extension in extensions) + { + problemDetails.Extensions.Add(extension); + } + } + + return new Problem(problemDetails); + } + + /// + /// Produces a response. + /// + /// The URI at which the content has been created. + /// The created for the response. + public static Created Created(string uri) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); + } + + return new(uri); + } + + /// + /// Produces a response. + /// + /// The URI at which the content has been created. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Created Created(string uri, TValue? value) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); + } + + return new(uri, value); + } + + /// + /// Produces a response. + /// + /// The URI at which the content has been created. + /// The created for the response. + public static Created Created(Uri uri) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); + } + + return new(uri); + } + + /// + /// Produces a response. + /// + /// The URI at which the content has been created. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Created Created(Uri uri, TValue? value) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); + } + + return new(uri, value); + } + + /// + /// Produces a response. + /// + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + /// The created for the response. + public static CreatedAtRoute CreatedAtRoute(string? routeName = null, object? routeValues = null) + => new(routeName, routeValues); + + /// + /// Produces a response. + /// + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static CreatedAtRoute CreatedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) + => new(routeName, routeValues, value); + + /// + /// Produces a response. + /// + /// The URI with the location at which the status of requested content can be monitored. + /// The created for the response. + public static Accepted Accepted(string uri) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); + } + + return new(uri); + } + + /// + /// Produces a response. + /// + /// The URI with the location at which the status of requested content can be monitored. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Accepted Accepted(string uri, TValue? value) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); + } + + return new(uri, value); + } + + /// + /// Produces a response. + /// + /// The URI with the location at which the status of requested content can be monitored. + /// The created for the response. + public static Accepted Accepted(Uri uri) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); + } + + return new(uri); + } + + /// + /// Produces a response. + /// + /// The URI with the location at which the status of requested content can be monitored. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Accepted Accepted(Uri uri, TValue? value) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); + } + + return new(uri, value); + } + + /// + /// Produces a response. + /// + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + /// The created for the response. + public static AcceptedAtRoute AcceptedAtRoute(string? routeName = null, object? routeValues = null) + => new(routeName, routeValues); + + /// + /// Produces a response. + /// + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static AcceptedAtRoute AcceptedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) + => new(routeName, routeValues, value); + } +} diff --git a/src/Http/Http.Results/src/Results.cs b/src/Http/Http.Results/src/Results.cs index 35187a07d435..e6f0a5e69cc9 100644 --- a/src/Http/Http.Results/src/Results.cs +++ b/src/Http/Http.Results/src/Results.cs @@ -7,6 +7,7 @@ using System.Text.Json; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; @@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Http; /// /// A factory for . /// -public static class Results +public static partial class Results { /// /// Creates an that on execution invokes . @@ -32,7 +33,7 @@ public static class Results public static IResult Challenge( AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new ChallengeHttpResult(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + => new Challenge(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); /// /// Creates a that on execution invokes . @@ -50,7 +51,7 @@ public static IResult Challenge( /// a redirect to show a login page. /// public static IResult Forbid(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new ForbidHttpResult(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + => new Forbid(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); /// /// Creates an that on execution invokes . @@ -63,7 +64,7 @@ public static IResult SignIn( ClaimsPrincipal principal, AuthenticationProperties? properties = null, string? authenticationScheme = null) - => new SignInHttpResult(principal, authenticationScheme, properties); + => new SignIn(principal, authenticationScheme, properties); /// /// Creates an that on execution invokes . @@ -72,7 +73,7 @@ public static IResult SignIn( /// The authentication scheme to use for the sign-out operation. /// The created for the response. public static IResult SignOut(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new SignOutHttpResult(authenticationSchemes ?? Array.Empty(), properties); + => new SignOut(authenticationSchemes ?? Array.Empty(), properties); /// /// Writes the string to the HTTP response. @@ -114,7 +115,7 @@ public static IResult Text(string content, string? contentType = null, Encoding? mediaTypeHeaderValue.Encoding = contentEncoding ?? mediaTypeHeaderValue.Encoding; } - return new ContentHttpResult(content, mediaTypeHeaderValue?.ToString()); + return new Content(content, mediaTypeHeaderValue?.ToString()); } /// @@ -124,7 +125,7 @@ public static IResult Text(string content, string? contentType = null, Encoding? /// The content type (MIME type). /// The created object for the response. public static IResult Content(string content, MediaTypeHeaderValue contentType) - => new ContentHttpResult(content, contentType.ToString()); + => new Content(content, contentType.ToString()); /// /// Creates a that serializes the specified object to JSON. @@ -133,12 +134,12 @@ public static IResult Content(string content, MediaTypeHeaderValue contentType) /// The serializer options to use when serializing the value. /// The content-type to set on the response. /// The status code to set on the response. - /// The created that serializes the specified + /// The created that serializes the specified /// as JSON format for the response. /// Callers should cache an instance of serializer settings to avoid /// recreating cached data with each call. public static IResult Json(object? data, JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) - => new JsonHttpResult(data, statusCode, options) + => new Json(data, statusCode, options) { ContentType = contentType, }; @@ -153,11 +154,11 @@ public static IResult Json(object? data, JsonSerializerOptions? options = null, /// This API is an alias for . /// /// The file contents. - /// The Content-Type of the file. - /// The suggested file name. - /// Set to true to enable range requests processing. - /// The of when the file was last modified. - /// The associated with the file. + /// The Content-Type of the file. + /// The suggested file name. + /// Set to true to enable range requests processing. + /// The of when the file was last modified. + /// The associated with the file. /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static IResult File( @@ -168,7 +169,7 @@ public static IResult File( bool enableRangeProcessing = false, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - => new FileContentHttpResult(fileContents, contentType) + => new FileContent(fileContents, contentType) { FileDownloadName = fileDownloadName, EnableRangeProcessing = enableRangeProcessing, @@ -199,7 +200,7 @@ public static IResult Bytes( bool enableRangeProcessing = false, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - => new FileContentHttpResult(contents, contentType) + => new FileContent(contents, contentType) { FileDownloadName = fileDownloadName, EnableRangeProcessing = enableRangeProcessing, @@ -230,7 +231,7 @@ public static IResult Bytes( bool enableRangeProcessing = false, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - => new FileContentHttpResult(contents, contentType) + => new FileContent(contents, contentType) { FileDownloadName = fileDownloadName, EnableRangeProcessing = enableRangeProcessing, @@ -270,7 +271,7 @@ public static IResult File( EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) { - return new FileStreamHttpResult(fileStream, contentType) + return new HttpFileStream(fileStream, contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -309,7 +310,7 @@ public static IResult Stream( EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) { - return new FileStreamHttpResult(stream, contentType) + return new HttpFileStream(stream, contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -347,7 +348,7 @@ public static IResult Stream( EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) { - return new FileStreamHttpResult(pipeReader.AsStream(), contentType) + return new HttpFileStream(pipeReader.AsStream(), contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -380,7 +381,7 @@ public static IResult Stream( DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) { - return new PushStreamHttpResult(streamWriterCallback, contentType) + return new PushStream(streamWriterCallback, contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -414,7 +415,7 @@ public static IResult File( { if (Path.IsPathRooted(path)) { - return new PhysicalFileHttpResult(path, contentType) + return new PhysicalFile(path, contentType) { FileDownloadName = fileDownloadName, LastModified = lastModified, @@ -424,7 +425,7 @@ public static IResult File( } else { - return new VirtualFileHttpResult(path, contentType) + return new VirtualFile(path, contentType) { FileDownloadName = fileDownloadName, LastModified = lastModified, @@ -448,7 +449,7 @@ public static IResult File( /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. /// The created for the response. public static IResult Redirect(string url, bool permanent = false, bool preserveMethod = false) - => new RedirectHttpResult(url, permanent, preserveMethod); + => new Redirect(url, permanent, preserveMethod); /// /// Redirects to the specified . @@ -464,7 +465,7 @@ public static IResult Redirect(string url, bool permanent = false, bool preserve /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. /// The created for the response. public static IResult LocalRedirect(string localUrl, bool permanent = false, bool preserveMethod = false) - => new RedirectHttpResult(localUrl, acceptLocalUrlOnly: true, permanent, preserveMethod); + => new Redirect(localUrl, acceptLocalUrlOnly: true, permanent, preserveMethod); /// /// Redirects to the specified route. @@ -482,7 +483,7 @@ public static IResult LocalRedirect(string localUrl, bool permanent = false, boo /// The fragment to add to the URL. /// The created for the response. public static IResult RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) - => new RedirectToRouteHttpResult( + => new RedirectToRoute( routeName: routeName, routeValues: routeValues, permanent: permanent, @@ -490,10 +491,10 @@ public static IResult RedirectToRoute(string? routeName = null, object? routeVal fragment: fragment); /// - /// Creates a object by specifying a . + /// Creates a object by specifying a . /// /// The status code to set on the response. - /// The created object for the response. + /// The created object for the response. public static IResult StatusCode(int statusCode) => ResultsCache.StatusCode(statusCode); @@ -586,7 +587,7 @@ public static IResult Problem( } } - return new ProblemHttpResult(problemDetails); + return new Problem(problemDetails); } /// @@ -596,7 +597,7 @@ public static IResult Problem( /// The created for the response. public static IResult Problem(ProblemDetails problemDetails) { - return new ProblemHttpResult(problemDetails); + return new Problem(problemDetails); } /// @@ -638,7 +639,7 @@ public static IResult ValidationProblem( } } - return new ProblemHttpResult(problemDetails); + return new Problem(problemDetails); } /// @@ -654,7 +655,7 @@ public static IResult Created(string uri, object? value) throw new ArgumentNullException(nameof(uri)); } - return new CreatedHttpResult(uri, value); + return new Created(uri, value); } /// @@ -670,7 +671,7 @@ public static IResult Created(Uri uri, object? value) throw new ArgumentNullException(nameof(uri)); } - return new CreatedHttpResult(uri, value); + return new Created(uri, value); } /// @@ -681,7 +682,7 @@ public static IResult Created(Uri uri, object? value) /// The value to be included in the HTTP response body. /// The created for the response. public static IResult CreatedAtRoute(string? routeName = null, object? routeValues = null, object? value = null) - => new CreatedAtRouteHttpResult(routeName, routeValues, value); + => new CreatedAtRoute(routeName, routeValues, value); /// /// Produces a response. @@ -690,7 +691,7 @@ public static IResult CreatedAtRoute(string? routeName = null, object? routeValu /// The optional content value to format in the response body. /// The created for the response. public static IResult Accepted(string? uri = null, object? value = null) - => new AcceptedHttpResult(uri, value); + => new Accepted(uri, value); /// /// Produces a response. @@ -700,12 +701,12 @@ public static IResult Accepted(string? uri = null, object? value = null) /// The optional content value to format in the response body. /// The created for the response. public static IResult AcceptedAtRoute(string? routeName = null, object? routeValues = null, object? value = null) - => new AcceptedAtRouteHttpResult(routeName, routeValues, value); + => new AcceptedAtRoute(routeName, routeValues, value); /// /// Produces an empty result response, that when executed will do nothing. /// - public static IResult Empty { get; } = EmptyHttpResult.Instance; + public static IResult Empty { get; } = HttpResults.Empty.Instance; /// /// Provides a container for external libraries to extend diff --git a/src/Http/Http.Results/src/SignInHttpResult.cs b/src/Http/Http.Results/src/SignIn.cs similarity index 86% rename from src/Http/Http.Results/src/SignInHttpResult.cs rename to src/Http/Http.Results/src/SignIn.cs index a1b0d805e867..678c9cc85968 100644 --- a/src/Http/Http.Results/src/SignInHttpResult.cs +++ b/src/Http/Http.Results/src/SignIn.cs @@ -6,31 +6,31 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that on execution invokes . /// -public sealed partial class SignInHttpResult : IResult +public sealed partial class SignIn : IResult { /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// default authentication scheme. /// /// The claims principal containing the user claims. - internal SignInHttpResult(ClaimsPrincipal principal) + internal SignIn(ClaimsPrincipal principal) : this(principal, authenticationScheme: null, properties: null) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme and . /// /// The claims principal containing the user claims. /// The authentication schemes to use when signing in the user. /// used to perform the sign-in operation. - internal SignInHttpResult(ClaimsPrincipal principal, string? authenticationScheme, AuthenticationProperties? properties) + internal SignIn(ClaimsPrincipal principal, string? authenticationScheme, AuthenticationProperties? properties) { Principal = principal ?? throw new ArgumentNullException(nameof(principal)); AuthenticationScheme = authenticationScheme; diff --git a/src/Http/Http.Results/src/SignOutHttpResult.cs b/src/Http/Http.Results/src/SignOut.cs similarity index 79% rename from src/Http/Http.Results/src/SignOutHttpResult.cs rename to src/Http/Http.Results/src/SignOut.cs index 7d187fe52c15..e3c53f645f3b 100644 --- a/src/Http/Http.Results/src/SignOutHttpResult.cs +++ b/src/Http/Http.Results/src/SignOut.cs @@ -6,69 +6,69 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that on execution invokes . /// -public sealed partial class SignOutHttpResult : IResult +public sealed partial class SignOut : IResult { /// - /// Initializes a new instance of with the default sign out scheme. + /// Initializes a new instance of with the default sign out scheme. /// - internal SignOutHttpResult() + internal SignOut() : this(Array.Empty()) { } /// - /// Initializes a new instance of with the default sign out scheme. + /// Initializes a new instance of with the default sign out scheme. /// specified authentication scheme and . /// /// used to perform the sign-out operation. - internal SignOutHttpResult(AuthenticationProperties properties) + internal SignOut(AuthenticationProperties properties) : this(Array.Empty(), properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme. /// /// The authentication scheme to use when signing out the user. - internal SignOutHttpResult(string authenticationScheme) + internal SignOut(string authenticationScheme) : this(new[] { authenticationScheme }) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes. /// /// The authentication schemes to use when signing out the user. - internal SignOutHttpResult(IList authenticationSchemes) + internal SignOut(IList authenticationSchemes) : this(authenticationSchemes, properties: null) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme and . /// /// The authentication schemes to use when signing out the user. /// used to perform the sign-out operation. - internal SignOutHttpResult(string authenticationScheme, AuthenticationProperties? properties) + internal SignOut(string authenticationScheme, AuthenticationProperties? properties) : this(new[] { authenticationScheme }, properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes and . /// /// The authentication scheme to use when signing out the user. /// used to perform the sign-out operation. - internal SignOutHttpResult(IList authenticationSchemes, AuthenticationProperties? properties) + internal SignOut(IList authenticationSchemes, AuthenticationProperties? properties) { if (authenticationSchemes is null) { diff --git a/src/Http/Http.Results/src/StatusCodeHttpResult.cs b/src/Http/Http.Results/src/Status.cs similarity index 86% rename from src/Http/Http.Results/src/StatusCodeHttpResult.cs rename to src/Http/Http.Results/src/Status.cs index 3e24b45a7767..e83d618a6a4a 100644 --- a/src/Http/Http.Results/src/StatusCodeHttpResult.cs +++ b/src/Http/Http.Results/src/Status.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,14 +10,14 @@ namespace Microsoft.AspNetCore.Http; /// Represents an that when executed will /// produce an HTTP response with the given response status code. /// -public sealed partial class StatusCodeHttpResult : IResult +public sealed partial class Status : IResult { /// - /// Initializes a new instance of the class + /// Initializes a new instance of the class /// with the given . /// /// The HTTP status code of the response. - internal StatusCodeHttpResult(int statusCode) + internal Status(int statusCode) { StatusCode = statusCode; } diff --git a/src/Http/Http.Results/src/UnauthorizedHttpResult.cs b/src/Http/Http.Results/src/Unauthorized.cs similarity index 88% rename from src/Http/Http.Results/src/UnauthorizedHttpResult.cs rename to src/Http/Http.Results/src/Unauthorized.cs index 79bc2c17dd91..cabd9202f1b2 100644 --- a/src/Http/Http.Results/src/UnauthorizedHttpResult.cs +++ b/src/Http/Http.Results/src/Unauthorized.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,12 +10,12 @@ namespace Microsoft.AspNetCore.Http; /// Represents an that when executed will /// produce an HTTP response with the No Unauthorized (401) status code. /// -public sealed class UnauthorizedHttpResult : IResult +public sealed class Unauthorized : IResult { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - internal UnauthorizedHttpResult() + internal Unauthorized() { } diff --git a/src/Http/Http.Results/src/UnprocessableEntity.cs b/src/Http/Http.Results/src/UnprocessableEntity.cs new file mode 100644 index 000000000000..4a763a46e656 --- /dev/null +++ b/src/Http/Http.Results/src/UnprocessableEntity.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +/// +/// An that on execution will write an object to the response +/// with Unprocessable Entity (422) status code. +/// +public sealed class UnprocessableEntity : IResult +{ + /// + /// Initializes a new instance of the class with the values + /// provided. + /// + internal UnprocessableEntity() + { + } + + /// > + public int StatusCode => StatusCodes.Status422UnprocessableEntity; + + /// + public Task ExecuteAsync(HttpContext httpContext) + { + // Creating the logger with a string to preserve the category after the refactoring. + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.UnprocessableEntityObjectResult"); + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return Task.CompletedTask; + } +} diff --git a/src/Http/Http.Results/src/UnprocessableEntityObjectHttpResult.cs b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs similarity index 77% rename from src/Http/Http.Results/src/UnprocessableEntityObjectHttpResult.cs rename to src/Http/Http.Results/src/UnprocessableEntityOfT.cs index d1c8eda62dae..6ff4a5d87b1e 100644 --- a/src/Http/Http.Results/src/UnprocessableEntityObjectHttpResult.cs +++ b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,21 +10,21 @@ namespace Microsoft.AspNetCore.Http; /// An that on execution will write an object to the response /// with Unprocessable Entity (422) status code. /// -public sealed class UnprocessableEntityObjectHttpResult : IResult +public sealed class UnprocessableEntity : IResult { /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The value to format in the entity body. - internal UnprocessableEntityObjectHttpResult(object? value) + internal UnprocessableEntity(TValue? value) { Value = value; HttpResultsHelper.ApplyProblemDetailsDefaultsIfNeeded(Value, StatusCode); } /// - public object? Value { get; internal init; } + public TValue? Value { get; } /// > public int StatusCode => StatusCodes.Status422UnprocessableEntity; @@ -36,10 +36,12 @@ public Task ExecuteAsync(HttpContext httpContext) var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.UnprocessableEntityObjectResult"); + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + return HttpResultsHelper.WriteResultAsJsonAsync( httpContext, logger: logger, - Value, - StatusCode); + Value); } } diff --git a/src/Http/Http.Results/src/VirtualFileHttpResult.cs b/src/Http/Http.Results/src/VirtualFile.cs similarity index 92% rename from src/Http/Http.Results/src/VirtualFileHttpResult.cs rename to src/Http/Http.Results/src/VirtualFile.cs index cac64665d23d..05ae588f79d9 100644 --- a/src/Http/Http.Results/src/VirtualFileHttpResult.cs +++ b/src/Http/Http.Results/src/VirtualFile.cs @@ -8,36 +8,36 @@ using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// A that on execution writes the file specified /// using a virtual path to the response using mechanisms provided by the host. /// -public sealed class VirtualFileHttpResult : IResult +public sealed class VirtualFile : IResult { private string _fileName; /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. - internal VirtualFileHttpResult(string fileName, string? contentType) + internal VirtualFile(string fileName, string? contentType) : this(fileName, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. /// The suggested file name. - internal VirtualFileHttpResult( + internal VirtualFile( string fileName, string? contentType, string? fileDownloadName) @@ -46,7 +46,7 @@ internal VirtualFileHttpResult( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. @@ -54,7 +54,7 @@ internal VirtualFileHttpResult( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal VirtualFileHttpResult( + internal VirtualFile( string fileName, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs b/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs index ae0b8f754085..c4c3c09b51c0 100644 --- a/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs +++ b/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs @@ -20,7 +20,7 @@ public void AcceptedAtRouteResult_ProblemDetails_SetsStatusCodeAndValue() { "sample", "route" } }); var obj = new HttpValidationProblemDetails(); - var result = new AcceptedAtRouteHttpResult(routeValues, obj); + var result = new AcceptedAtRoute(routeValues, obj); // Assert Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); @@ -45,7 +45,7 @@ public async Task ExecuteResultAsync_FormatsData() }); // Act - var result = new AcceptedAtRouteHttpResult( + var result = new AcceptedAtRoute( routeName: "sample", routeValues: routeValues, value: "Hello world"); @@ -87,7 +87,7 @@ public async Task ExecuteResultAsync_SetsStatusCodeAndLocationHeader(object valu var httpContext = GetHttpContext(linkGenerator); // Act - var result = new AcceptedAtRouteHttpResult(routeValues: values, value: null); + var result = new AcceptedAtRoute(routeValues: values, value: null); await result.ExecuteAsync(httpContext); // Assert @@ -103,7 +103,7 @@ public async Task ExecuteResultAsync_ThrowsIfRouteUrlIsNull() var httpContext = GetHttpContext(linkGenerator); // Act - var result = new AcceptedAtRouteHttpResult( + var result = new AcceptedAtRoute( routeName: null, routeValues: new Dictionary(), value: null); diff --git a/src/Http/Http.Results/test/AcceptedResultTests.cs b/src/Http/Http.Results/test/AcceptedResultTests.cs index 9cf5eb6bbfb8..3ffc4b6e2306 100644 --- a/src/Http/Http.Results/test/AcceptedResultTests.cs +++ b/src/Http/Http.Results/test/AcceptedResultTests.cs @@ -16,7 +16,7 @@ public async Task ExecuteResultAsync_FormatsData() var stream = new MemoryStream(); httpContext.Response.Body = stream; // Act - var result = new AcceptedHttpResult("my-location", value: "Hello world"); + var result = new Accepted("my-location", value: "Hello world"); await result.ExecuteAsync(httpContext); // Assert @@ -32,7 +32,7 @@ public async Task ExecuteResultAsync_SetsStatusCodeAndLocationHeader() var httpContext = GetHttpContext(); // Act - var result = new AcceptedHttpResult(expectedUrl, value: "some-value"); + var result = new Accepted(expectedUrl, value: "some-value"); await result.ExecuteAsync(httpContext); // Assert @@ -46,7 +46,7 @@ public void AcceptedResult_ProblemDetails_SetsStatusCodeAndValue() // Arrange & Act var expectedUrl = "testAction"; var obj = new HttpValidationProblemDetails(); - var result = new AcceptedHttpResult(expectedUrl, obj); + var result = new Accepted(expectedUrl, obj); // Assert Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); diff --git a/src/Http/Http.Results/test/BadRequestObjectResultTests.cs b/src/Http/Http.Results/test/BadRequestObjectResultTests.cs index c72a82752af1..faf9b3f8c4ed 100644 --- a/src/Http/Http.Results/test/BadRequestObjectResultTests.cs +++ b/src/Http/Http.Results/test/BadRequestObjectResultTests.cs @@ -15,7 +15,7 @@ public void BadRequestObjectResult_SetsStatusCodeAndValue() { // Arrange & Act var obj = new object(); - var badRequestObjectResult = new BadRequestObjectHttpResult(obj); + var badRequestObjectResult = new BadRequest(obj); // Assert Assert.Equal(StatusCodes.Status400BadRequest, badRequestObjectResult.StatusCode); @@ -27,7 +27,7 @@ public void BadRequestObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new HttpValidationProblemDetails(); - var result = new BadRequestObjectHttpResult(obj); + var result = new BadRequest(obj); // Assert Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); @@ -39,7 +39,7 @@ public void BadRequestObjectResult_ProblemDetails_SetsStatusCodeAndValue() public async Task BadRequestObjectResult_ExecuteAsync_SetsStatusCode() { // Arrange - var result = new BadRequestObjectHttpResult("Hello"); + var result = new BadRequest("Hello"); var httpContext = new DefaultHttpContext() { RequestServices = CreateServices(), @@ -56,7 +56,7 @@ public async Task BadRequestObjectResult_ExecuteAsync_SetsStatusCode() public async Task BadRequestObjectResult_ExecuteResultAsync_FormatsData() { // Arrange - var result = new BadRequestObjectHttpResult("Hello"); + var result = new BadRequest("Hello"); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/ConflictObjectResultTest.cs b/src/Http/Http.Results/test/ConflictObjectResultTest.cs index 091d03bc605f..a65c128e60ab 100644 --- a/src/Http/Http.Results/test/ConflictObjectResultTest.cs +++ b/src/Http/Http.Results/test/ConflictObjectResultTest.cs @@ -16,7 +16,7 @@ public void ConflictObjectResult_SetsStatusCodeAndValue() { // Arrange & Act var obj = new object(); - var conflictObjectResult = new ConflictObjectHttpResult(obj); + var conflictObjectResult = new Conflict(obj); // Assert Assert.Equal(StatusCodes.Status409Conflict, conflictObjectResult.StatusCode); @@ -28,7 +28,7 @@ public void ConflictObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new ProblemDetails(); - var conflictObjectResult = new ConflictObjectHttpResult(obj); + var conflictObjectResult = new Conflict(obj); // Assert Assert.Equal(StatusCodes.Status409Conflict, conflictObjectResult.StatusCode); @@ -40,7 +40,7 @@ public void ConflictObjectResult_ProblemDetails_SetsStatusCodeAndValue() public async Task ConflictObjectResult_ExecuteAsync_SetsStatusCode() { // Arrange - var result = new ConflictObjectHttpResult("Hello"); + var result = new Conflict("Hello"); var httpContext = new DefaultHttpContext() { RequestServices = CreateServices(), @@ -57,7 +57,7 @@ public async Task ConflictObjectResult_ExecuteAsync_SetsStatusCode() public async Task ConflictObjectResult_ExecuteResultAsync_FormatsData() { // Arrange - var result = new ConflictObjectHttpResult("Hello"); + var result = new Conflict("Hello"); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs b/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs index 5fd0575a3c35..f740a66d99dc 100644 --- a/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs +++ b/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs @@ -21,7 +21,7 @@ public void CreatedAtRouteResult_ProblemDetails_SetsStatusCodeAndValue() { "sample", "route" } }); var obj = new HttpValidationProblemDetails(); - var result = new CreatedAtRouteHttpResult(routeValues, obj); + var result = new CreatedAtRoute(routeValues, obj); // Assert Assert.Equal(StatusCodes.Status201Created, result.StatusCode); @@ -56,7 +56,7 @@ public async Task CreatedAtRouteResult_ReturnsStatusCode_SetsLocationHeader(obje var httpContext = GetHttpContext(expectedUrl); // Act - var result = new CreatedAtRouteHttpResult(routeName: null, routeValues: values, value: null); + var result = new CreatedAtRoute(routeName: null, routeValues: values, value: null); await result.ExecuteAsync(httpContext); // Assert @@ -70,7 +70,7 @@ public async Task CreatedAtRouteResult_ThrowsOnNullUrl() // Arrange var httpContext = GetHttpContext(expectedUrl: null); - var result = new CreatedAtRouteHttpResult( + var result = new CreatedAtRoute( routeName: null, routeValues: new Dictionary(), value: null); diff --git a/src/Http/Http.Results/test/FileContentResultTest.cs b/src/Http/Http.Results/test/FileContentResultTest.cs index 1628bcc8da6d..3220b17d805f 100644 --- a/src/Http/Http.Results/test/FileContentResultTest.cs +++ b/src/Http/Http.Results/test/FileContentResultTest.cs @@ -19,7 +19,7 @@ protected override Task ExecuteAsync( EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { - var result = new FileContentHttpResult(buffer, contentType) + var result = new FileContent(buffer, contentType) { EntityTag = entityTag, LastModified = lastModified, diff --git a/src/Http/Http.Results/test/FileStreamResultTest.cs b/src/Http/Http.Results/test/FileStreamResultTest.cs index 82f7939da79a..2b7bd64ad9e2 100644 --- a/src/Http/Http.Results/test/FileStreamResultTest.cs +++ b/src/Http/Http.Results/test/FileStreamResultTest.cs @@ -16,7 +16,7 @@ protected override Task ExecuteAsync( EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { - var fileStreamResult = new FileStreamHttpResult(stream, contentType) + var fileStreamResult = new FileStream(stream, contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -33,7 +33,7 @@ public void Constructor_SetsFileName() var stream = Stream.Null; // Act - var result = new FileStreamHttpResult(stream, "text/plain"); + var result = new FileStream(stream, "text/plain"); // Assert Assert.Equal(stream, result.FileStream); @@ -48,7 +48,7 @@ public void Constructor_SetsContentTypeAndParameters() var expectedMediaType = contentType; // Act - var result = new FileStreamHttpResult(stream, contentType); + var result = new FileStream(stream, contentType); // Assert Assert.Equal(stream, result.FileStream); @@ -66,7 +66,7 @@ public void Constructor_SetsLastModifiedAndEtag() var entityTag = new EntityTagHeaderValue("\"Etag\""); // Act - var result = new FileStreamHttpResult(stream, contentType) + var result = new FileStream(stream, contentType) { LastModified = lastModified, EntityTag = entityTag, diff --git a/src/Http/Http.Results/test/ForbidResultTest.cs b/src/Http/Http.Results/test/ForbidResultTest.cs index d3b770178ded..a1a4f08b6c12 100644 --- a/src/Http/Http.Results/test/ForbidResultTest.cs +++ b/src/Http/Http.Results/test/ForbidResultTest.cs @@ -22,7 +22,7 @@ public async Task ExecuteResultAsync_InvokesForbidAsyncOnAuthenticationService() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new ForbidHttpResult("", null); + var result = new Forbid("", null); // Act await result.ExecuteAsync(httpContext); @@ -46,7 +46,7 @@ public async Task ExecuteResultAsync_InvokesForbidAsyncOnAllConfiguredSchemes() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new ForbidHttpResult(new[] { "Scheme1", "Scheme2" }, authProperties); + var result = new Forbid(new[] { "Scheme1", "Scheme2" }, authProperties); var routeData = new RouteData(); // Act @@ -73,7 +73,7 @@ public async Task ExecuteResultAsync_InvokesForbidAsyncWithAuthProperties(Authen .Setup(c => c.ForbidAsync(It.IsAny(), null, expected)) .Returns(Task.CompletedTask) .Verifiable(); - var result = new ForbidHttpResult(expected); + var result = new Forbid(expected); var httpContext = GetHttpContext(auth.Object); // Act @@ -95,7 +95,7 @@ public async Task ExecuteResultAsync_InvokesForbidAsyncWithAuthProperties_WhenAu .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new ForbidHttpResult(expected) + var result = new Forbid(expected) { AuthenticationSchemes = new string[0] }; diff --git a/src/Http/Http.Results/test/LocalRedirectResultTest.cs b/src/Http/Http.Results/test/LocalRedirectResultTest.cs index 33e49752fefd..2d7275951883 100644 --- a/src/Http/Http.Results/test/LocalRedirectResultTest.cs +++ b/src/Http/Http.Results/test/LocalRedirectResultTest.cs @@ -16,7 +16,7 @@ public void Constructor_WithParameterUrl_SetsResultUrlAndNotPermanentOrPreserveM var url = "/test/url"; // Act - var result = new RedirectHttpResult(url, acceptLocalUrlOnly: true, false, false); + var result = new Redirect(url, acceptLocalUrlOnly: true, false, false); // Assert Assert.False(result.PreserveMethod); @@ -31,7 +31,7 @@ public void Constructor_WithParameterUrlAndPermanent_SetsResultUrlAndPermanentNo var url = "/test/url"; // Act - var result = new RedirectHttpResult(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: false); + var result = new Redirect(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: false); // Assert Assert.False(result.PreserveMethod); @@ -46,7 +46,7 @@ public void Constructor_WithParameterUrlAndPermanent_SetsResultUrlPermanentAndPr var url = "/test/url"; // Act - var result = new RedirectHttpResult(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: true); + var result = new Redirect(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: true); // Assert Assert.True(result.PreserveMethod); @@ -63,7 +63,7 @@ public async Task Execute_ReturnsExpectedValues() var expectedPath = "/Home/About"; var httpContext = GetHttpContext(appRoot); - var result = new RedirectHttpResult(contentPath, acceptLocalUrlOnly: true, false, false); + var result = new Redirect(contentPath, acceptLocalUrlOnly: true, false, false); // Act await result.ExecuteAsync(httpContext); @@ -86,7 +86,7 @@ public async Task Execute_Throws_ForNonLocalUrl( { // Arrange var httpContext = GetHttpContext(appRoot); - var result = new RedirectHttpResult(contentPath, acceptLocalUrlOnly: true, false, false); + var result = new Redirect(contentPath, acceptLocalUrlOnly: true, false, false); // Act & Assert var exception = await Assert.ThrowsAsync(() => result.ExecuteAsync(httpContext)); @@ -107,7 +107,7 @@ public async Task Execute_Throws_ForNonLocalUrlTilde( { // Arrange var httpContext = GetHttpContext(appRoot); - var result = new RedirectHttpResult(contentPath, acceptLocalUrlOnly: true, false, false); + var result = new Redirect(contentPath, acceptLocalUrlOnly: true, false, false); // Act & Assert var exception = await Assert.ThrowsAsync(() => result.ExecuteAsync(httpContext)); diff --git a/src/Http/Http.Results/test/NoContentResultTests.cs b/src/Http/Http.Results/test/NoContentResultTests.cs index 18b56774b6f5..21ff07de11a6 100644 --- a/src/Http/Http.Results/test/NoContentResultTests.cs +++ b/src/Http/Http.Results/test/NoContentResultTests.cs @@ -13,7 +13,7 @@ public class NoContentResultTests public void NoContentResultTests_InitializesStatusCode() { // Arrange & act - var result = new NoContentHttpResult(); + var result = new NoContent(); // Assert Assert.Equal(StatusCodes.Status204NoContent, result.StatusCode); @@ -23,7 +23,7 @@ public void NoContentResultTests_InitializesStatusCode() public void NoContentResultTests_ExecuteResultSetsResponseStatusCode() { // Arrange - var result = new NoContentHttpResult(); + var result = new NoContent(); var httpContext = GetHttpContext(); diff --git a/src/Http/Http.Results/test/NotFoundObjectResultTest.cs b/src/Http/Http.Results/test/NotFoundObjectResultTest.cs index b9c4426e1b40..7e333b3138f7 100644 --- a/src/Http/Http.Results/test/NotFoundObjectResultTest.cs +++ b/src/Http/Http.Results/test/NotFoundObjectResultTest.cs @@ -14,7 +14,7 @@ public void NotFoundObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new HttpValidationProblemDetails(); - var result = new NotFoundObjectHttpResult(obj); + var result = new NotFound(obj); // Assert Assert.Equal(StatusCodes.Status404NotFound, result.StatusCode); @@ -26,7 +26,7 @@ public void NotFoundObjectResult_ProblemDetails_SetsStatusCodeAndValue() public void NotFoundObjectResult_InitializesStatusCode() { // Arrange & act - var notFound = new NotFoundObjectHttpResult(null); + var notFound = new NotFound(null); // Assert Assert.Equal(StatusCodes.Status404NotFound, notFound.StatusCode); @@ -36,7 +36,7 @@ public void NotFoundObjectResult_InitializesStatusCode() public void NotFoundObjectResult_InitializesStatusCodeAndResponseContent() { // Arrange & act - var notFound = new NotFoundObjectHttpResult("Test Content"); + var notFound = new NotFound("Test Content"); // Assert Assert.Equal(StatusCodes.Status404NotFound, notFound.StatusCode); @@ -48,7 +48,7 @@ public async Task NotFoundObjectResult_ExecuteSuccessful() { // Arrange var httpContext = GetHttpContext(); - var result = new NotFoundObjectHttpResult("Test Content"); + var result = new NotFound("Test Content"); // Act await result.ExecuteAsync(httpContext); diff --git a/src/Http/Http.Results/test/ObjectResultTests.cs b/src/Http/Http.Results/test/ObjectResultTests.cs index 9e81802a9788..004fc40c2ac0 100644 --- a/src/Http/Http.Results/test/ObjectResultTests.cs +++ b/src/Http/Http.Results/test/ObjectResultTests.cs @@ -175,7 +175,7 @@ public async Task ExecuteAsync_UsesStatusCodeFromResultTypeForProblemDetails() // Arrange var details = new ProblemDetails { Status = StatusCodes.Status422UnprocessableEntity, }; - var result = new BadRequestObjectHttpResult(details); + var result = new BadRequest(details); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/OkObjectResultTest.cs b/src/Http/Http.Results/test/OkObjectResultTest.cs index 64d4d85a8a82..783d35cce821 100644 --- a/src/Http/Http.Results/test/OkObjectResultTest.cs +++ b/src/Http/Http.Results/test/OkObjectResultTest.cs @@ -14,7 +14,7 @@ public class OkObjectResultTest public async Task OkObjectResult_SetsStatusCodeAndValue() { // Arrange - var result = new OkObjectHttpResult("Hello world"); + var result = new Ok("Hello world"); var httpContext = GetHttpContext(); // Act @@ -29,7 +29,7 @@ public void OkObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new HttpValidationProblemDetails(); - var result = new OkObjectHttpResult(obj); + var result = new Ok(obj); // Assert Assert.Equal(StatusCodes.Status200OK, result.StatusCode); @@ -41,7 +41,7 @@ public void OkObjectResult_ProblemDetails_SetsStatusCodeAndValue() public async Task OkObjectResult_ExecuteAsync_FormatsData() { // Arrange - var result = new OkObjectHttpResult("Hello"); + var result = new Ok("Hello"); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/PhysicalFileResultTest.cs b/src/Http/Http.Results/test/PhysicalFileResultTest.cs index 6ba0c2f0b64a..7654ce38d24e 100644 --- a/src/Http/Http.Results/test/PhysicalFileResultTest.cs +++ b/src/Http/Http.Results/test/PhysicalFileResultTest.cs @@ -16,7 +16,7 @@ protected override Task ExecuteAsync( EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { - var fileResult = new PhysicalFileHttpResult(path, contentType) + var fileResult = new PhysicalFile(path, contentType) { LastModified = lastModified, EntityTag = entityTag, diff --git a/src/Http/Http.Results/test/ProblemResultTests.cs b/src/Http/Http.Results/test/ProblemResultTests.cs index 28dfd0653cd8..16187de2d5a8 100644 --- a/src/Http/Http.Results/test/ProblemResultTests.cs +++ b/src/Http/Http.Results/test/ProblemResultTests.cs @@ -17,7 +17,7 @@ public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() // Arrange var details = new ProblemDetails(); - var result = new ProblemHttpResult(details); + var result = new Problem(details); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -46,7 +46,7 @@ public async Task ExecuteAsync_UsesDefaults_ForValidationProblemDetails() // Arrange var details = new HttpValidationProblemDetails(); - var result = new ProblemHttpResult(details); + var result = new Problem(details); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -75,7 +75,7 @@ public async Task ExecuteAsync_GetsStatusCodeFromProblemDetails() // Arrange var details = new ProblemDetails { Status = StatusCodes.Status413RequestEntityTooLarge, }; - var result = new ProblemHttpResult(details); + var result = new Problem(details); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/PushStreamResultTest.cs b/src/Http/Http.Results/test/PushStreamResultTest.cs index a4791775dc75..5a9c8a48857f 100644 --- a/src/Http/Http.Results/test/PushStreamResultTest.cs +++ b/src/Http/Http.Results/test/PushStreamResultTest.cs @@ -12,7 +12,7 @@ public class PushStreamResultTest [Fact] public async Task PushStreamResultsExposeTheResponseBody() { - var result = new PushStreamHttpResult(body => body.WriteAsync(Encoding.UTF8.GetBytes("Hello World").AsMemory()).AsTask(), contentType: null); + var result = new PushStream(body => body.WriteAsync(Encoding.UTF8.GetBytes("Hello World").AsMemory()).AsTask(), contentType: null); var httpContext = new DefaultHttpContext { @@ -37,7 +37,7 @@ public void Constructor_SetsContentTypeAndParameters() var callback = (Stream body) => body.WriteAsync(Encoding.UTF8.GetBytes("Hello World").AsMemory()).AsTask(); // Act - var result = new PushStreamHttpResult(callback, contentType); + var result = new PushStream(callback, contentType); // Assert Assert.Equal(expectedMediaType, result.ContentType); @@ -55,7 +55,7 @@ public void Constructor_SetsLastModifiedAndEtag() var callback = (Stream body) => body.WriteAsync(Encoding.UTF8.GetBytes("Hello World").AsMemory()).AsTask(); // Act - var result = new PushStreamHttpResult(callback, contentType) + var result = new PushStream(callback, contentType) { LastModified = lastModified, EntityTag = entityTag, diff --git a/src/Http/Http.Results/test/RedirectResultTest.cs b/src/Http/Http.Results/test/RedirectResultTest.cs index 207e6c6850b9..328270b0f430 100644 --- a/src/Http/Http.Results/test/RedirectResultTest.cs +++ b/src/Http/Http.Results/test/RedirectResultTest.cs @@ -14,7 +14,7 @@ public void RedirectResult_Constructor_WithParameterUrlPermanentAndPreservesMeth var url = "/test/url"; // Act - var result = new RedirectHttpResult(url, permanent: true, preserveMethod: true); + var result = new Redirect(url, permanent: true, preserveMethod: true); // Assert Assert.True(result.PreserveMethod); @@ -24,7 +24,7 @@ public void RedirectResult_Constructor_WithParameterUrlPermanentAndPreservesMeth protected override Task ExecuteAsync(HttpContext httpContext, string contentPath) { - var redirectResult = new RedirectHttpResult(contentPath, false, false); + var redirectResult = new Redirect(contentPath, false, false); return redirectResult.ExecuteAsync(httpContext); } } diff --git a/src/Http/Http.Results/test/RedirectToRouteResultTest.cs b/src/Http/Http.Results/test/RedirectToRouteResultTest.cs index 99dcac7836dc..1a78532351e5 100644 --- a/src/Http/Http.Results/test/RedirectToRouteResultTest.cs +++ b/src/Http/Http.Results/test/RedirectToRouteResultTest.cs @@ -18,7 +18,7 @@ public async Task RedirectToRoute_Execute_ThrowsOnNullUrl() var httpContext = new DefaultHttpContext(); httpContext.RequestServices = CreateServices(null).BuildServiceProvider(); - var result = new RedirectToRouteHttpResult(null, new Dictionary()); + var result = new RedirectToRoute(null, new Dictionary()); // Act & Assert await ExceptionAssert.ThrowsAsync( @@ -38,7 +38,7 @@ public async Task ExecuteResultAsync_UsesRouteName_ToGenerateLocationHeader() var httpContext = GetHttpContext(locationUrl); - var result = new RedirectToRouteHttpResult(routeName, new { id = 10 }); + var result = new RedirectToRoute(routeName, new { id = 10 }); // Act await result.ExecuteAsync(httpContext); @@ -56,7 +56,7 @@ public async Task ExecuteResultAsync_WithFragment_PassesCorrectValuesToRedirect( var expectedStatusCode = StatusCodes.Status301MovedPermanently; var httpContext = GetHttpContext(expectedUrl); - var result = new RedirectToRouteHttpResult("Sample", null, true, "test"); + var result = new RedirectToRoute("Sample", null, true, "test"); // Act await result.ExecuteAsync(httpContext); @@ -74,7 +74,7 @@ public async Task ExecuteResultAsync_WithFragment_PassesCorrectValuesToRedirect_ var expectedStatusCode = StatusCodes.Status308PermanentRedirect; var httpContext = GetHttpContext(expectedUrl); - var result = new RedirectToRouteHttpResult("Sample", null, true, true, "test"); + var result = new RedirectToRoute("Sample", null, true, true, "test"); // Act await result.ExecuteAsync(httpContext); diff --git a/src/Http/Http.Results/test/SignInResultTest.cs b/src/Http/Http.Results/test/SignInResultTest.cs index 6aef97223c54..be658e406f7e 100644 --- a/src/Http/Http.Results/test/SignInResultTest.cs +++ b/src/Http/Http.Results/test/SignInResultTest.cs @@ -24,7 +24,7 @@ public async Task ExecuteAsync_InvokesSignInAsyncOnAuthenticationManager() .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignInHttpResult(principal, "", null); + var result = new SignIn(principal, "", null); // Act await result.ExecuteAsync(httpContext); @@ -44,7 +44,7 @@ public async Task ExecuteAsync_InvokesSignInAsyncOnAuthenticationManagerWithDefa .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignInHttpResult(principal); + var result = new SignIn(principal); // Act await result.ExecuteAsync(httpContext); @@ -65,7 +65,7 @@ public async Task ExecuteAsync_InvokesSignInAsyncOnConfiguredScheme() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignInHttpResult(principal, "Scheme1", authProperties); + var result = new SignIn(principal, "Scheme1", authProperties); // Act await result.ExecuteAsync(httpContext); diff --git a/src/Http/Http.Results/test/SignOutResultTest.cs b/src/Http/Http.Results/test/SignOutResultTest.cs index d3cfa5073659..bfb8ad534c66 100644 --- a/src/Http/Http.Results/test/SignOutResultTest.cs +++ b/src/Http/Http.Results/test/SignOutResultTest.cs @@ -21,7 +21,7 @@ public async Task ExecuteAsync_NoArgsInvokesDefaultSignOut() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignOutHttpResult(); + var result = new SignOut(); // Act await result.ExecuteAsync(httpContext); @@ -40,7 +40,7 @@ public async Task ExecuteAsync_InvokesSignOutAsyncOnAuthenticationManager() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignOutHttpResult("", null); + var result = new SignOut("", null); // Act await result.ExecuteAsync(httpContext); @@ -64,7 +64,7 @@ public async Task ExecuteAsync_InvokesSignOutAsyncOnAllConfiguredSchemes() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignOutHttpResult(new[] { "Scheme1", "Scheme2" }, authProperties); + var result = new SignOut(new[] { "Scheme1", "Scheme2" }, authProperties); // Act await result.ExecuteAsync(httpContext); diff --git a/src/Http/Http.Results/test/StatusCodeResultTests.cs b/src/Http/Http.Results/test/StatusCodeResultTests.cs index ae3493329307..a8be6bea2fe8 100644 --- a/src/Http/Http.Results/test/StatusCodeResultTests.cs +++ b/src/Http/Http.Results/test/StatusCodeResultTests.cs @@ -13,7 +13,7 @@ public class StatusCodeResultTests public void StatusCodeResult_ExecuteResultSetsResponseStatusCode() { // Arrange - var result = new StatusCodeHttpResult(StatusCodes.Status404NotFound); + var result = new StatusCode(StatusCodes.Status404NotFound); var httpContext = GetHttpContext(); diff --git a/src/Http/Http.Results/test/UnauthorizedResultTests.cs b/src/Http/Http.Results/test/UnauthorizedResultTests.cs index 50aab7fd7bf9..c28b17dd7789 100644 --- a/src/Http/Http.Results/test/UnauthorizedResultTests.cs +++ b/src/Http/Http.Results/test/UnauthorizedResultTests.cs @@ -13,7 +13,7 @@ public class UnauthorizedResultTests public void UnauthorizedResult_InitializesStatusCode() { // Arrange & act - var result = new UnauthorizedHttpResult(); + var result = new Unauthorized(); // Assert Assert.Equal(StatusCodes.Status401Unauthorized, result.StatusCode); @@ -23,7 +23,7 @@ public void UnauthorizedResult_InitializesStatusCode() public void UnauthorizedResult_ExecuteResultSetsResponseStatusCode() { // Arrange - var result = new UnauthorizedHttpResult(); + var result = new Unauthorized(); var httpContext = GetHttpContext(); diff --git a/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs b/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs index f04410925e29..b3b9b74e72e1 100644 --- a/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs +++ b/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs @@ -15,7 +15,7 @@ public void NotFoundObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new HttpValidationProblemDetails(); - var result = new UnprocessableEntityObjectHttpResult(obj); + var result = new UnprocessableEntity(obj); // Assert Assert.Equal(StatusCodes.Status422UnprocessableEntity, result.StatusCode); @@ -28,7 +28,7 @@ public void UnprocessableEntityObjectResult_SetsStatusCodeAndValue() { // Arrange & Act var obj = new object(); - var result = new UnprocessableEntityObjectHttpResult(obj); + var result = new UnprocessableEntity(obj); // Assert Assert.Equal(StatusCodes.Status422UnprocessableEntity, result.StatusCode); @@ -39,7 +39,7 @@ public void UnprocessableEntityObjectResult_SetsStatusCodeAndValue() public async Task UnprocessableEntityObjectResult_ExecuteAsync_SetsStatusCode() { // Arrange - var result = new UnprocessableEntityObjectHttpResult("Hello"); + var result = new UnprocessableEntity("Hello"); var httpContext = new DefaultHttpContext() { RequestServices = CreateServices(), @@ -56,7 +56,7 @@ public async Task UnprocessableEntityObjectResult_ExecuteAsync_SetsStatusCode() public async Task UnprocessableEntityObjectResult_ExecuteResultAsync_FormatsData() { // Arrange - var result = new UnprocessableEntityObjectHttpResult("Hello"); + var result = new UnprocessableEntity("Hello"); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/VirtualFileResultTest.cs b/src/Http/Http.Results/test/VirtualFileResultTest.cs index d910676c5365..30acf59b830a 100644 --- a/src/Http/Http.Results/test/VirtualFileResultTest.cs +++ b/src/Http/Http.Results/test/VirtualFileResultTest.cs @@ -10,7 +10,7 @@ public class VirtualFileResultTest : VirtualFileResultTestBase { protected override Task ExecuteAsync(HttpContext httpContext, string path, string contentType, DateTimeOffset? lastModified = null, EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { - var result = new VirtualFileHttpResult(path, contentType) + var result = new VirtualFile(path, contentType) { LastModified = lastModified, EntityTag = entityTag, diff --git a/src/submodules/googletest b/src/submodules/googletest index 80600e56cc9a..af29db7ec28d 160000 --- a/src/submodules/googletest +++ b/src/submodules/googletest @@ -1 +1 @@ -Subproject commit 80600e56cc9afe7ee02737429f9177aa87025054 +Subproject commit af29db7ec28d6df1c7f0f745186884091e602e07 From fa070bc77ee2f745d0335d338077557da7f46fbc Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Fri, 8 Apr 2022 14:54:12 -0700 Subject: [PATCH 02/35] Updating unit tests --- .../src/{Results.Typed.cs => TypedResults.cs} | 6 +- .../test/AcceptedAtRouteOfTResultTests.cs | 131 ++++++++++++++++++ .../test/AcceptedAtRouteResultTests.cs | 53 +------ .../test/AcceptedOfTResultTests.cs | 70 ++++++++++ .../Http.Results/test/AcceptedResultTests.cs | 34 +---- ...ltTests.cs => BadRequestOfTResultTests.cs} | 12 +- .../test/BadRequestResultTests.cs | 46 ++++++ .../Http.Results/test/ChallengeResultTest.cs | 6 +- ...ResultTest.cs => ConflictOfTResultTest.cs} | 12 +- .../Http.Results/test/ConflictResultTest.cs | 47 +++++++ .../Http.Results/test/ContentResultTest.cs | 6 +- .../test/CreatedAtRouteOfTResultTests.cs | 104 ++++++++++++++ .../test/CreatedAtRouteResultTests.cs | 24 +--- .../test/CreatedOfTResultTests.cs | 108 +++++++++++++++ ...tedResultTest.cs => CreatedResultTests.cs} | 22 +-- src/Http/Http.Results/test/EmptyResultTest.cs | 4 +- .../test/FileContentResultTest.cs | 2 +- .../Http.Results/test/FileStreamResultTest.cs | 2 +- .../Http.Results/test/ForbidResultTest.cs | 2 +- .../test/LocalRedirectResultTest.cs | 2 +- .../Http.Results/test/NoContentResultTests.cs | 2 +- .../test/NotFoundObjectResultTest.cs | 2 +- .../Http.Results/test/ObjectResultTests.cs | 2 +- .../Http.Results/test/OkObjectResultTest.cs | 2 +- .../test/PhysicalFileResultTest.cs | 2 +- .../Http.Results/test/ProblemResultTests.cs | 2 +- .../Http.Results/test/PushStreamResultTest.cs | 2 +- .../Http.Results/test/RedirectResultTest.cs | 2 +- .../test/RedirectToRouteResultTest.cs | 2 +- .../Http.Results/test/SignInResultTest.cs | 2 +- .../Http.Results/test/SignOutResultTest.cs | 2 +- .../test/StatusCodeResultTests.cs | 2 +- .../Http.Results/test/TestLinkGenerator.cs | 2 +- .../test/UnauthorizedResultTests.cs | 2 +- .../UnprocessableEntityObjectResultTests.cs | 2 +- .../test/VirtualFileResultTest.cs | 2 +- 36 files changed, 561 insertions(+), 164 deletions(-) rename src/Http/Http.Results/src/{Results.Typed.cs => TypedResults.cs} (99%) create mode 100644 src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs create mode 100644 src/Http/Http.Results/test/AcceptedOfTResultTests.cs rename src/Http/Http.Results/test/{BadRequestObjectResultTests.cs => BadRequestOfTResultTests.cs} (86%) create mode 100644 src/Http/Http.Results/test/BadRequestResultTests.cs rename src/Http/Http.Results/test/{ConflictObjectResultTest.cs => ConflictOfTResultTest.cs} (87%) create mode 100644 src/Http/Http.Results/test/ConflictResultTest.cs create mode 100644 src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs create mode 100644 src/Http/Http.Results/test/CreatedOfTResultTests.cs rename src/Http/Http.Results/test/{CreatedResultTest.cs => CreatedResultTests.cs} (73%) diff --git a/src/Http/Http.Results/src/Results.Typed.cs b/src/Http/Http.Results/src/TypedResults.cs similarity index 99% rename from src/Http/Http.Results/src/Results.Typed.cs rename to src/Http/Http.Results/src/TypedResults.cs index 00dc7072d8db..f219bbcf9048 100644 --- a/src/Http/Http.Results/src/Results.Typed.cs +++ b/src/Http/Http.Results/src/TypedResults.cs @@ -632,7 +632,7 @@ public static Problem Problem( } } - return new Problem(problemDetails); + return new(problemDetails); } /// @@ -642,7 +642,7 @@ public static Problem Problem( /// The created for the response. public static Problem Problem(ProblemDetails problemDetails) { - return new Problem(problemDetails); + return new(problemDetails); } /// @@ -684,7 +684,7 @@ public static Problem ValidationProblem( } } - return new Problem(problemDetails); + return new(problemDetails); } /// diff --git a/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs b/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs new file mode 100644 index 000000000000..efca3f97e17d --- /dev/null +++ b/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs @@ -0,0 +1,131 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +public class AcceptedAtRouteOfTResultTests +{ + [Fact] + public void AcceptedAtRouteResult_ProblemDetails_SetsStatusCodeAndValue() + { + // Arrange & Act + var routeValues = new RouteValueDictionary(new Dictionary() + { + { "test", "case" }, + { "sample", "route" } + }); + var obj = new HttpValidationProblemDetails(); + var result = new AcceptedAtRoute(routeValues, obj); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(StatusCodes.Status202Accepted, obj.Status); + Assert.Equal(obj, result.Value); + } + + [Fact] + public async Task ExecuteResultAsync_FormatsData() + { + // Arrange + var url = "testAction"; + var linkGenerator = new TestLinkGenerator { Url = url }; + var httpContext = GetHttpContext(linkGenerator); + var stream = new MemoryStream(); + httpContext.Response.Body = stream; + + var routeValues = new RouteValueDictionary(new Dictionary() + { + { "test", "case" }, + { "sample", "route" } + }); + + // Act + var result = new AcceptedAtRoute( + routeName: "sample", + routeValues: routeValues, + value: "Hello world"); + await result.ExecuteAsync(httpContext); + + // Assert + var response = Encoding.UTF8.GetString(stream.ToArray()); + Assert.Equal("\"Hello world\"", response); + } + + public static TheoryData AcceptedAtRouteData + { + get + { + return new TheoryData + { + null, + new Dictionary() + { + { "hello", "world" } + }, + new RouteValueDictionary( + new Dictionary() + { + { "test", "case" }, + { "sample", "route" } + }), + }; + } + } + + [Theory] + [MemberData(nameof(AcceptedAtRouteData))] + public async Task ExecuteResultAsync_SetsStatusCodeAndLocationHeader(object values) + { + // Arrange + var expectedUrl = "testAction"; + var linkGenerator = new TestLinkGenerator { Url = expectedUrl }; + var httpContext = GetHttpContext(linkGenerator); + + // Act + var result = new AcceptedAtRoute(routeValues: values, value: null); + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, httpContext.Response.StatusCode); + Assert.Equal(expectedUrl, httpContext.Response.Headers["Location"]); + } + + [Fact] + public async Task ExecuteResultAsync_ThrowsIfRouteUrlIsNull() + { + // Arrange + var linkGenerator = new TestLinkGenerator(); + var httpContext = GetHttpContext(linkGenerator); + + // Act + var result = new AcceptedAtRoute( + routeName: null, + routeValues: new Dictionary(), + value: null); + + // Assert + await ExceptionAssert.ThrowsAsync(() => + result.ExecuteAsync(httpContext), + "No route matches the supplied values."); + } + + private static HttpContext GetHttpContext(LinkGenerator linkGenerator) + { + var httpContext = new DefaultHttpContext(); + httpContext.RequestServices = CreateServices(linkGenerator); + return httpContext; + } + + private static IServiceProvider CreateServices(LinkGenerator linkGenerator) + { + var services = new ServiceCollection(); + services.AddLogging(); + services.AddSingleton(linkGenerator); + return services.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs b/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs index c4c3c09b51c0..3bc4ea61530d 100644 --- a/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs +++ b/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs @@ -6,56 +6,10 @@ using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class AcceptedAtRouteResultTests { - [Fact] - public void AcceptedAtRouteResult_ProblemDetails_SetsStatusCodeAndValue() - { - // Arrange & Act - var routeValues = new RouteValueDictionary(new Dictionary() - { - { "test", "case" }, - { "sample", "route" } - }); - var obj = new HttpValidationProblemDetails(); - var result = new AcceptedAtRoute(routeValues, obj); - - // Assert - Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); - Assert.Equal(StatusCodes.Status202Accepted, obj.Status); - Assert.Equal(obj, result.Value); - } - - [Fact] - public async Task ExecuteResultAsync_FormatsData() - { - // Arrange - var url = "testAction"; - var linkGenerator = new TestLinkGenerator { Url = url }; - var httpContext = GetHttpContext(linkGenerator); - var stream = new MemoryStream(); - httpContext.Response.Body = stream; - - var routeValues = new RouteValueDictionary(new Dictionary() - { - { "test", "case" }, - { "sample", "route" } - }); - - // Act - var result = new AcceptedAtRoute( - routeName: "sample", - routeValues: routeValues, - value: "Hello world"); - await result.ExecuteAsync(httpContext); - - // Assert - var response = Encoding.UTF8.GetString(stream.ToArray()); - Assert.Equal("\"Hello world\"", response); - } - public static TheoryData AcceptedAtRouteData { get @@ -87,7 +41,7 @@ public async Task ExecuteResultAsync_SetsStatusCodeAndLocationHeader(object valu var httpContext = GetHttpContext(linkGenerator); // Act - var result = new AcceptedAtRoute(routeValues: values, value: null); + var result = new AcceptedAtRoute(routeValues: values); await result.ExecuteAsync(httpContext); // Assert @@ -105,8 +59,7 @@ public async Task ExecuteResultAsync_ThrowsIfRouteUrlIsNull() // Act var result = new AcceptedAtRoute( routeName: null, - routeValues: new Dictionary(), - value: null); + routeValues: new Dictionary()); // Assert await ExceptionAssert.ThrowsAsync(() => diff --git a/src/Http/Http.Results/test/AcceptedOfTResultTests.cs b/src/Http/Http.Results/test/AcceptedOfTResultTests.cs new file mode 100644 index 000000000000..9ad9dcdabdef --- /dev/null +++ b/src/Http/Http.Results/test/AcceptedOfTResultTests.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +public class AcceptedOfTResultTests +{ + [Fact] + public async Task ExecuteResultAsync_FormatsData() + { + // Arrange + var httpContext = GetHttpContext(); + var stream = new MemoryStream(); + httpContext.Response.Body = stream; + // Act + var result = new Accepted("my-location", value: "Hello world"); + await result.ExecuteAsync(httpContext); + + // Assert + var response = Encoding.UTF8.GetString(stream.ToArray()); + Assert.Equal("\"Hello world\"", response); + } + + [Fact] + public async Task ExecuteResultAsync_SetsStatusCodeAndLocationHeader() + { + // Arrange + var expectedUrl = "testAction"; + var httpContext = GetHttpContext(); + + // Act + var result = new Accepted(expectedUrl, value: "some-value"); + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, httpContext.Response.StatusCode); + Assert.Equal(expectedUrl, httpContext.Response.Headers["Location"]); + } + + [Fact] + public void AcceptedResult_ProblemDetails_SetsStatusCodeAndValue() + { + // Arrange & Act + var expectedUrl = "testAction"; + var obj = new HttpValidationProblemDetails(); + var result = new Accepted(expectedUrl, obj); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(StatusCodes.Status202Accepted, obj.Status); + Assert.Equal(obj, result.Value); + } + + private static HttpContext GetHttpContext() + { + var httpContext = new DefaultHttpContext(); + httpContext.RequestServices = CreateServices(); + return httpContext; + } + + private static IServiceProvider CreateServices() + { + var services = new ServiceCollection(); + services.AddLogging(); + return services.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Results/test/AcceptedResultTests.cs b/src/Http/Http.Results/test/AcceptedResultTests.cs index 3ffc4b6e2306..8d5bd2d3499a 100644 --- a/src/Http/Http.Results/test/AcceptedResultTests.cs +++ b/src/Http/Http.Results/test/AcceptedResultTests.cs @@ -4,26 +4,10 @@ using System.Text; using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class AcceptedResultTests { - [Fact] - public async Task ExecuteResultAsync_FormatsData() - { - // Arrange - var httpContext = GetHttpContext(); - var stream = new MemoryStream(); - httpContext.Response.Body = stream; - // Act - var result = new Accepted("my-location", value: "Hello world"); - await result.ExecuteAsync(httpContext); - - // Assert - var response = Encoding.UTF8.GetString(stream.ToArray()); - Assert.Equal("\"Hello world\"", response); - } - [Fact] public async Task ExecuteResultAsync_SetsStatusCodeAndLocationHeader() { @@ -32,7 +16,7 @@ public async Task ExecuteResultAsync_SetsStatusCodeAndLocationHeader() var httpContext = GetHttpContext(); // Act - var result = new Accepted(expectedUrl, value: "some-value"); + var result = new Accepted(expectedUrl); await result.ExecuteAsync(httpContext); // Assert @@ -40,20 +24,6 @@ public async Task ExecuteResultAsync_SetsStatusCodeAndLocationHeader() Assert.Equal(expectedUrl, httpContext.Response.Headers["Location"]); } - [Fact] - public void AcceptedResult_ProblemDetails_SetsStatusCodeAndValue() - { - // Arrange & Act - var expectedUrl = "testAction"; - var obj = new HttpValidationProblemDetails(); - var result = new Accepted(expectedUrl, obj); - - // Assert - Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); - Assert.Equal(StatusCodes.Status202Accepted, obj.Status); - Assert.Equal(obj, result.Value); - } - private static HttpContext GetHttpContext() { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/BadRequestObjectResultTests.cs b/src/Http/Http.Results/test/BadRequestOfTResultTests.cs similarity index 86% rename from src/Http/Http.Results/test/BadRequestObjectResultTests.cs rename to src/Http/Http.Results/test/BadRequestOfTResultTests.cs index faf9b3f8c4ed..b3f963028016 100644 --- a/src/Http/Http.Results/test/BadRequestObjectResultTests.cs +++ b/src/Http/Http.Results/test/BadRequestOfTResultTests.cs @@ -1,21 +1,21 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; using System.Text; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -public class BadRequestObjectResultTests +public class BadRequestOfTResultTests { [Fact] public void BadRequestObjectResult_SetsStatusCodeAndValue() { // Arrange & Act var obj = new object(); - var badRequestObjectResult = new BadRequest(obj); + var badRequestObjectResult = new BadRequest(obj); // Assert Assert.Equal(StatusCodes.Status400BadRequest, badRequestObjectResult.StatusCode); @@ -27,7 +27,7 @@ public void BadRequestObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new HttpValidationProblemDetails(); - var result = new BadRequest(obj); + var result = new BadRequest(obj); // Assert Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); @@ -39,7 +39,7 @@ public void BadRequestObjectResult_ProblemDetails_SetsStatusCodeAndValue() public async Task BadRequestObjectResult_ExecuteAsync_SetsStatusCode() { // Arrange - var result = new BadRequest("Hello"); + var result = new BadRequest("Hello"); var httpContext = new DefaultHttpContext() { RequestServices = CreateServices(), @@ -56,7 +56,7 @@ public async Task BadRequestObjectResult_ExecuteAsync_SetsStatusCode() public async Task BadRequestObjectResult_ExecuteResultAsync_FormatsData() { // Arrange - var result = new BadRequest("Hello"); + var result = new BadRequest("Hello"); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/BadRequestResultTests.cs b/src/Http/Http.Results/test/BadRequestResultTests.cs new file mode 100644 index 000000000000..7d181ab45e35 --- /dev/null +++ b/src/Http/Http.Results/test/BadRequestResultTests.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +public class BadRequestResultTests +{ + [Fact] + public void BadRequestObjectResult_SetsStatusCodeA() + { + // Arrange & Act + var badRequestResult = new BadRequest(); + + // Assert + Assert.Equal(StatusCodes.Status400BadRequest, badRequestResult.StatusCode); + } + + [Fact] + public async Task BadRequestObjectResult_ExecuteAsync_SetsStatusCode() + { + // Arrange + var result = new BadRequest(); + var httpContext = new DefaultHttpContext() + { + RequestServices = CreateServices(), + }; + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); + } + + private static IServiceProvider CreateServices() + { + var services = new ServiceCollection(); + services.AddSingleton(); + return services.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Results/test/ChallengeResultTest.cs b/src/Http/Http.Results/test/ChallengeResultTest.cs index 95817e6ba449..2e49139758ac 100644 --- a/src/Http/Http.Results/test/ChallengeResultTest.cs +++ b/src/Http/Http.Results/test/ChallengeResultTest.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class ChallengeResultTest { @@ -15,7 +15,7 @@ public class ChallengeResultTest public async Task ChallengeResult_ExecuteAsync() { // Arrange - var result = new ChallengeHttpResult("", null); + var result = new Challenge("", null); var auth = new Mock(); var httpContext = GetHttpContext(auth); @@ -30,7 +30,7 @@ public async Task ChallengeResult_ExecuteAsync() public async Task ChallengeResult_ExecuteAsync_NoSchemes() { // Arrange - var result = new ChallengeHttpResult(new string[] { }, null); + var result = new Challenge(new string[] { }, null); var auth = new Mock(); var httpContext = GetHttpContext(auth); diff --git a/src/Http/Http.Results/test/ConflictObjectResultTest.cs b/src/Http/Http.Results/test/ConflictOfTResultTest.cs similarity index 87% rename from src/Http/Http.Results/test/ConflictObjectResultTest.cs rename to src/Http/Http.Results/test/ConflictOfTResultTest.cs index a65c128e60ab..c5454408ec59 100644 --- a/src/Http/Http.Results/test/ConflictObjectResultTest.cs +++ b/src/Http/Http.Results/test/ConflictOfTResultTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; using System.Text; using Microsoft.AspNetCore.Mvc; @@ -9,14 +9,14 @@ namespace Microsoft.AspNetCore.Http.Result; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -public class ConflictObjectResultTest +public class ConflictOfTResultTest { [Fact] public void ConflictObjectResult_SetsStatusCodeAndValue() { // Arrange & Act var obj = new object(); - var conflictObjectResult = new Conflict(obj); + var conflictObjectResult = new Conflict(obj); // Assert Assert.Equal(StatusCodes.Status409Conflict, conflictObjectResult.StatusCode); @@ -28,7 +28,7 @@ public void ConflictObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new ProblemDetails(); - var conflictObjectResult = new Conflict(obj); + var conflictObjectResult = new Conflict(obj); // Assert Assert.Equal(StatusCodes.Status409Conflict, conflictObjectResult.StatusCode); @@ -40,7 +40,7 @@ public void ConflictObjectResult_ProblemDetails_SetsStatusCodeAndValue() public async Task ConflictObjectResult_ExecuteAsync_SetsStatusCode() { // Arrange - var result = new Conflict("Hello"); + var result = new Conflict("Hello"); var httpContext = new DefaultHttpContext() { RequestServices = CreateServices(), @@ -57,7 +57,7 @@ public async Task ConflictObjectResult_ExecuteAsync_SetsStatusCode() public async Task ConflictObjectResult_ExecuteResultAsync_FormatsData() { // Arrange - var result = new Conflict("Hello"); + var result = new Conflict("Hello"); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/ConflictResultTest.cs b/src/Http/Http.Results/test/ConflictResultTest.cs new file mode 100644 index 000000000000..7c53821d55e8 --- /dev/null +++ b/src/Http/Http.Results/test/ConflictResultTest.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using System.Text; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +public class ConflictResultTest +{ + [Fact] + public void ConflictObjectResult_SetsStatusCode() + { + // Arrange & Act + var conflictObjectResult = new Conflict(); + + // Assert + Assert.Equal(StatusCodes.Status409Conflict, conflictObjectResult.StatusCode); + } + + [Fact] + public async Task ConflictObjectResult_ExecuteAsync_SetsStatusCode() + { + // Arrange + var result = new Conflict(); + var httpContext = new DefaultHttpContext() + { + RequestServices = CreateServices(), + }; + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status409Conflict, httpContext.Response.StatusCode); + } + + private static IServiceProvider CreateServices() + { + var services = new ServiceCollection(); + services.AddSingleton(); + return services.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Results/test/ContentResultTest.cs b/src/Http/Http.Results/test/ContentResultTest.cs index f45ea77e6226..276e234cbed9 100644 --- a/src/Http/Http.Results/test/ContentResultTest.cs +++ b/src/Http/Http.Results/test/ContentResultTest.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class ContentResultTest { @@ -20,7 +20,7 @@ public async Task ContentResult_ExecuteAsync_Response_NullContent_SetsContentTyp Encoding = Encoding.Unicode }.ToString(); - var contentResult = new ContentHttpResult(null, contentType); + var contentResult = new Content(null, contentType); var httpContext = GetHttpContext(); // Act @@ -107,7 +107,7 @@ public async Task ContentResult_ExecuteAsync_SetContentTypeAndEncoding_OnRespons byte[] expectedContentData) { // Arrange - var contentResult = new ContentHttpResult(content, contentType?.ToString()); + var contentResult = new Content(content, contentType?.ToString()); var httpContext = GetHttpContext(); var memoryStream = new MemoryStream(); httpContext.Response.Body = memoryStream; diff --git a/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs b/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs new file mode 100644 index 000000000000..d1432d00dec9 --- /dev/null +++ b/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +public partial class CreatedAtRouteOfTResultTests +{ + [Fact] + public void CreatedAtRouteResult_ProblemDetails_SetsStatusCodeAndValue() + { + // Arrange & Act + var routeValues = new RouteValueDictionary(new Dictionary() + { + { "test", "case" }, + { "sample", "route" } + }); + var obj = new HttpValidationProblemDetails(); + var result = new CreatedAtRoute(routeValues, obj); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(StatusCodes.Status201Created, obj.Status); + Assert.Equal(obj, result.Value); + } + public static IEnumerable CreatedAtRouteData + { + get + { + yield return new object[] { null }; + yield return + new object[] { + new Dictionary() { { "hello", "world" } } + }; + yield return + new object[] { + new RouteValueDictionary(new Dictionary() { + { "test", "case" }, + { "sample", "route" } + }) + }; + } + } + + [Theory] + [MemberData(nameof(CreatedAtRouteData))] + public async Task CreatedAtRouteResult_ReturnsStatusCode_SetsLocationHeader(object values) + { + // Arrange + var expectedUrl = "testAction"; + var httpContext = GetHttpContext(expectedUrl); + + // Act + var result = new CreatedAtRoute(routeName: null, routeValues: values, value: null); + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status201Created, httpContext.Response.StatusCode); + Assert.Equal(expectedUrl, httpContext.Response.Headers["Location"]); + } + + [Fact] + public async Task CreatedAtRouteResult_ThrowsOnNullUrl() + { + // Arrange + var httpContext = GetHttpContext(expectedUrl: null); + + var result = new CreatedAtRoute( + routeName: null, + routeValues: new Dictionary(), + value: null); + + // Act & Assert + await ExceptionAssert.ThrowsAsync( + async () => await result.ExecuteAsync(httpContext), + "No route matches the supplied values."); + } + + private static HttpContext GetHttpContext(string expectedUrl) + { + var httpContext = new DefaultHttpContext(); + httpContext.Request.PathBase = new PathString(""); + httpContext.Response.Body = new MemoryStream(); + httpContext.RequestServices = CreateServices(expectedUrl); + return httpContext; + } + + private static IServiceProvider CreateServices(string expectedUrl) + { + var services = new ServiceCollection(); + services.AddSingleton(); + services.AddSingleton(new TestLinkGenerator + { + Url = expectedUrl + }); + + return services.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs b/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs index f740a66d99dc..292ee76ef924 100644 --- a/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs +++ b/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs @@ -7,27 +7,10 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public partial class CreatedAtRouteResultTests { - [Fact] - public void CreatedAtRouteResult_ProblemDetails_SetsStatusCodeAndValue() - { - // Arrange & Act - var routeValues = new RouteValueDictionary(new Dictionary() - { - { "test", "case" }, - { "sample", "route" } - }); - var obj = new HttpValidationProblemDetails(); - var result = new CreatedAtRoute(routeValues, obj); - - // Assert - Assert.Equal(StatusCodes.Status201Created, result.StatusCode); - Assert.Equal(StatusCodes.Status201Created, obj.Status); - Assert.Equal(obj, result.Value); - } public static IEnumerable CreatedAtRouteData { get @@ -56,7 +39,7 @@ public async Task CreatedAtRouteResult_ReturnsStatusCode_SetsLocationHeader(obje var httpContext = GetHttpContext(expectedUrl); // Act - var result = new CreatedAtRoute(routeName: null, routeValues: values, value: null); + var result = new CreatedAtRoute(routeName: null, routeValues: values); await result.ExecuteAsync(httpContext); // Assert @@ -72,8 +55,7 @@ public async Task CreatedAtRouteResult_ThrowsOnNullUrl() var result = new CreatedAtRoute( routeName: null, - routeValues: new Dictionary(), - value: null); + routeValues: new Dictionary()); // Act & Assert await ExceptionAssert.ThrowsAsync( diff --git a/src/Http/Http.Results/test/CreatedOfTResultTests.cs b/src/Http/Http.Results/test/CreatedOfTResultTests.cs new file mode 100644 index 000000000000..fa3c8ff372e4 --- /dev/null +++ b/src/Http/Http.Results/test/CreatedOfTResultTests.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +public class CreatedOfTResultTests +{ + [Fact] + public void CreatedResult_ProblemDetails_SetsStatusCodeAndValue() + { + // Arrange & Act + var expectedUrl = "testAction"; + var obj = new HttpValidationProblemDetails(); + var result = new Created(expectedUrl, obj); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(StatusCodes.Status201Created, obj.Status); + Assert.Equal(obj, result.Value); + } + + [Fact] + public void CreatedResult_SetsLocation() + { + // Arrange + var location = "http://test/location"; + + // Act + var result = new Created(location, "testInput"); + + // Assert + Assert.Same(location, result.Location); + } + + [Fact] + public async Task CreatedResult_ReturnsStatusCode_SetsLocationHeader() + { + // Arrange + var location = "/test/"; + var httpContext = GetHttpContext(); + var result = new Created(location, "testInput"); + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status201Created, httpContext.Response.StatusCode); + Assert.Equal(location, httpContext.Response.Headers["Location"]); + } + + [Fact] + public async Task CreatedResult_OverwritesLocationHeader() + { + // Arrange + var location = "/test/"; + var httpContext = GetHttpContext(); + httpContext.Response.Headers["Location"] = "/different/location/"; + var result = new Created(location, "testInput"); + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status201Created, httpContext.Response.StatusCode); + Assert.Equal(location, httpContext.Response.Headers["Location"]); + } + + [Fact] + public async Task CreatedResult_ExecuteResultAsync_FormatsData() + { + // Arrange + var location = "/test/"; + var httpContext = GetHttpContext(); + var stream = new MemoryStream(); + httpContext.Response.Body = stream; + httpContext.Response.Headers["Location"] = "/different/location/"; + var result = new Created(location, "testInput"); + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + var response = Encoding.UTF8.GetString(stream.ToArray()); + Assert.Equal("\"testInput\"", response); + } + + private static HttpContext GetHttpContext() + { + var httpContext = new DefaultHttpContext(); + httpContext.Request.PathBase = new PathString(""); + httpContext.Response.Body = new MemoryStream(); + httpContext.RequestServices = CreateServices(); + return httpContext; + } + + private static IServiceProvider CreateServices() + { + var services = new ServiceCollection(); + services.AddSingleton(); + + return services.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Results/test/CreatedResultTest.cs b/src/Http/Http.Results/test/CreatedResultTests.cs similarity index 73% rename from src/Http/Http.Results/test/CreatedResultTest.cs rename to src/Http/Http.Results/test/CreatedResultTests.cs index 2bc4b0ffa180..6feb00dab671 100644 --- a/src/Http/Http.Results/test/CreatedResultTest.cs +++ b/src/Http/Http.Results/test/CreatedResultTests.cs @@ -5,24 +5,10 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class CreatedResultTests { - [Fact] - public void CreatedResult_ProblemDetails_SetsStatusCodeAndValue() - { - // Arrange & Act - var expectedUrl = "testAction"; - var obj = new HttpValidationProblemDetails(); - var result = new CreatedHttpResult(expectedUrl, obj); - - // Assert - Assert.Equal(StatusCodes.Status201Created, result.StatusCode); - Assert.Equal(StatusCodes.Status201Created, obj.Status); - Assert.Equal(obj, result.Value); - } - [Fact] public void CreatedResult_SetsLocation() { @@ -30,7 +16,7 @@ public void CreatedResult_SetsLocation() var location = "http://test/location"; // Act - var result = new CreatedHttpResult(location, "testInput"); + var result = new Created(location); // Assert Assert.Same(location, result.Location); @@ -42,7 +28,7 @@ public async Task CreatedResult_ReturnsStatusCode_SetsLocationHeader() // Arrange var location = "/test/"; var httpContext = GetHttpContext(); - var result = new CreatedHttpResult(location, "testInput"); + var result = new Created(location); // Act await result.ExecuteAsync(httpContext); @@ -59,7 +45,7 @@ public async Task CreatedResult_OverwritesLocationHeader() var location = "/test/"; var httpContext = GetHttpContext(); httpContext.Response.Headers["Location"] = "/different/location/"; - var result = new CreatedHttpResult(location, "testInput"); + var result = new Created(location); // Act await result.ExecuteAsync(httpContext); diff --git a/src/Http/Http.Results/test/EmptyResultTest.cs b/src/Http/Http.Results/test/EmptyResultTest.cs index b8dd30d4dfff..74eb8ae20a01 100644 --- a/src/Http/Http.Results/test/EmptyResultTest.cs +++ b/src/Http/Http.Results/test/EmptyResultTest.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class EmptyResultTest { @@ -11,7 +11,7 @@ public class EmptyResultTest public async Task EmptyResult_DoesNothing() { // Arrange - var emptyResult = EmptyHttpResult.Instance; + var emptyResult = Empty.Instance; // Act var httpContext = GetHttpContext(); diff --git a/src/Http/Http.Results/test/FileContentResultTest.cs b/src/Http/Http.Results/test/FileContentResultTest.cs index 3220b17d805f..8f8ce8eb5f0c 100644 --- a/src/Http/Http.Results/test/FileContentResultTest.cs +++ b/src/Http/Http.Results/test/FileContentResultTest.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class FileContentResultTest : FileContentResultTestBase { diff --git a/src/Http/Http.Results/test/FileStreamResultTest.cs b/src/Http/Http.Results/test/FileStreamResultTest.cs index 2b7bd64ad9e2..286950535534 100644 --- a/src/Http/Http.Results/test/FileStreamResultTest.cs +++ b/src/Http/Http.Results/test/FileStreamResultTest.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Internal; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class FileStreamResultTest : FileStreamResultTestBase { diff --git a/src/Http/Http.Results/test/ForbidResultTest.cs b/src/Http/Http.Results/test/ForbidResultTest.cs index a1a4f08b6c12..be360a39847f 100644 --- a/src/Http/Http.Results/test/ForbidResultTest.cs +++ b/src/Http/Http.Results/test/ForbidResultTest.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class ForbidResultTest { diff --git a/src/Http/Http.Results/test/LocalRedirectResultTest.cs b/src/Http/Http.Results/test/LocalRedirectResultTest.cs index 2d7275951883..fe90f1566aec 100644 --- a/src/Http/Http.Results/test/LocalRedirectResultTest.cs +++ b/src/Http/Http.Results/test/LocalRedirectResultTest.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class LocalRedirectResultTest { diff --git a/src/Http/Http.Results/test/NoContentResultTests.cs b/src/Http/Http.Results/test/NoContentResultTests.cs index 21ff07de11a6..10c33f198771 100644 --- a/src/Http/Http.Results/test/NoContentResultTests.cs +++ b/src/Http/Http.Results/test/NoContentResultTests.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Http/Http.Results/test/NotFoundObjectResultTest.cs b/src/Http/Http.Results/test/NotFoundObjectResultTest.cs index 7e333b3138f7..164bad32b62e 100644 --- a/src/Http/Http.Results/test/NotFoundObjectResultTest.cs +++ b/src/Http/Http.Results/test/NotFoundObjectResultTest.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class NotFoundObjectResultTest { diff --git a/src/Http/Http.Results/test/ObjectResultTests.cs b/src/Http/Http.Results/test/ObjectResultTests.cs index 004fc40c2ac0..1a25ea2b7485 100644 --- a/src/Http/Http.Results/test/ObjectResultTests.cs +++ b/src/Http/Http.Results/test/ObjectResultTests.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class ObjectResultTests { diff --git a/src/Http/Http.Results/test/OkObjectResultTest.cs b/src/Http/Http.Results/test/OkObjectResultTest.cs index 783d35cce821..ab0aa1782339 100644 --- a/src/Http/Http.Results/test/OkObjectResultTest.cs +++ b/src/Http/Http.Results/test/OkObjectResultTest.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class OkObjectResultTest { diff --git a/src/Http/Http.Results/test/PhysicalFileResultTest.cs b/src/Http/Http.Results/test/PhysicalFileResultTest.cs index 7654ce38d24e..f63d50f71f95 100644 --- a/src/Http/Http.Results/test/PhysicalFileResultTest.cs +++ b/src/Http/Http.Results/test/PhysicalFileResultTest.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Internal; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class PhysicalFileResultTest : PhysicalFileResultTestBase { diff --git a/src/Http/Http.Results/test/ProblemResultTests.cs b/src/Http/Http.Results/test/ProblemResultTests.cs index 16187de2d5a8..f394f3d71328 100644 --- a/src/Http/Http.Results/test/ProblemResultTests.cs +++ b/src/Http/Http.Results/test/ProblemResultTests.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class ProblemResultTests { diff --git a/src/Http/Http.Results/test/PushStreamResultTest.cs b/src/Http/Http.Results/test/PushStreamResultTest.cs index 5a9c8a48857f..497b4f481c36 100644 --- a/src/Http/Http.Results/test/PushStreamResultTest.cs +++ b/src/Http/Http.Results/test/PushStreamResultTest.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class PushStreamResultTest { diff --git a/src/Http/Http.Results/test/RedirectResultTest.cs b/src/Http/Http.Results/test/RedirectResultTest.cs index 328270b0f430..20e1bcc7b652 100644 --- a/src/Http/Http.Results/test/RedirectResultTest.cs +++ b/src/Http/Http.Results/test/RedirectResultTest.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Internal; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class RedirectResultTest : RedirectResultTestBase { diff --git a/src/Http/Http.Results/test/RedirectToRouteResultTest.cs b/src/Http/Http.Results/test/RedirectToRouteResultTest.cs index 1a78532351e5..b7a503f40bbc 100644 --- a/src/Http/Http.Results/test/RedirectToRouteResultTest.cs +++ b/src/Http/Http.Results/test/RedirectToRouteResultTest.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class RedirectToRouteResultTest { diff --git a/src/Http/Http.Results/test/SignInResultTest.cs b/src/Http/Http.Results/test/SignInResultTest.cs index be658e406f7e..0c3c24274ace 100644 --- a/src/Http/Http.Results/test/SignInResultTest.cs +++ b/src/Http/Http.Results/test/SignInResultTest.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class SignInResultTest { diff --git a/src/Http/Http.Results/test/SignOutResultTest.cs b/src/Http/Http.Results/test/SignOutResultTest.cs index bfb8ad534c66..73438444def9 100644 --- a/src/Http/Http.Results/test/SignOutResultTest.cs +++ b/src/Http/Http.Results/test/SignOutResultTest.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class SignOutResultTest { diff --git a/src/Http/Http.Results/test/StatusCodeResultTests.cs b/src/Http/Http.Results/test/StatusCodeResultTests.cs index a8be6bea2fe8..1c9afcf9fb64 100644 --- a/src/Http/Http.Results/test/StatusCodeResultTests.cs +++ b/src/Http/Http.Results/test/StatusCodeResultTests.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class StatusCodeResultTests { diff --git a/src/Http/Http.Results/test/TestLinkGenerator.cs b/src/Http/Http.Results/test/TestLinkGenerator.cs index 38d6ea9fe92f..41b1aa1c2cb2 100644 --- a/src/Http/Http.Results/test/TestLinkGenerator.cs +++ b/src/Http/Http.Results/test/TestLinkGenerator.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Routing; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; internal sealed class TestLinkGenerator : LinkGenerator { diff --git a/src/Http/Http.Results/test/UnauthorizedResultTests.cs b/src/Http/Http.Results/test/UnauthorizedResultTests.cs index c28b17dd7789..fe6ce9979757 100644 --- a/src/Http/Http.Results/test/UnauthorizedResultTests.cs +++ b/src/Http/Http.Results/test/UnauthorizedResultTests.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs b/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs index b3b9b74e72e1..0396b469ec8b 100644 --- a/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs +++ b/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; using System.Text; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Http/Http.Results/test/VirtualFileResultTest.cs b/src/Http/Http.Results/test/VirtualFileResultTest.cs index 30acf59b830a..775afdabf1fb 100644 --- a/src/Http/Http.Results/test/VirtualFileResultTest.cs +++ b/src/Http/Http.Results/test/VirtualFileResultTest.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Internal; using Microsoft.Net.Http.Headers; -namespace Microsoft.AspNetCore.Http.Result; +namespace Microsoft.AspNetCore.Http.HttpResults; public class VirtualFileResultTest : VirtualFileResultTestBase { From 3989c839c835e9e15706138fc2d2bf158e9bdca9 Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Fri, 8 Apr 2022 15:09:16 -0700 Subject: [PATCH 03/35] Updating cache --- .../Microsoft.AspNetCore.Http.Results.csproj | 8 ++ .../src/ResultsCache.StatusCodes.cs | 129 +++++++++--------- .../src/ResultsCache.StatusCodes.tt | 9 +- src/Http/Http.Results/src/ResultsCache.cs | 16 ++- src/Http/Http.Results/src/TypedResults.cs | 16 +-- 5 files changed, 95 insertions(+), 83 deletions(-) diff --git a/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj b/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj index 0d9845104cc4..dc819c4ca160 100644 --- a/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj +++ b/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj @@ -33,6 +33,14 @@ + + + True + True + ResultsCache.StatusCodes.tt + + + TextTemplatingFileGenerator diff --git a/src/Http/Http.Results/src/ResultsCache.StatusCodes.cs b/src/Http/Http.Results/src/ResultsCache.StatusCodes.cs index 4e255cd9449c..394a8da16dd6 100644 --- a/src/Http/Http.Results/src/ResultsCache.StatusCodes.cs +++ b/src/Http/Http.Results/src/ResultsCache.StatusCodes.cs @@ -5,81 +5,82 @@ #nullable enable using System.CodeDom.Compiler; +using Microsoft.AspNetCore.Http.HttpResults; namespace Microsoft.AspNetCore.Http; [GeneratedCode("TextTemplatingFileGenerator", "")] internal partial class ResultsCache { - private static StatusCodeHttpResult? _status101SwitchingProtocols; - private static StatusCodeHttpResult? _status102Processing; - private static StatusCodeHttpResult? _status200OK; - private static StatusCodeHttpResult? _status201Created; - private static StatusCodeHttpResult? _status202Accepted; - private static StatusCodeHttpResult? _status203NonAuthoritative; - private static StatusCodeHttpResult? _status204NoContent; - private static StatusCodeHttpResult? _status205ResetContent; - private static StatusCodeHttpResult? _status206PartialContent; - private static StatusCodeHttpResult? _status207MultiStatus; - private static StatusCodeHttpResult? _status208AlreadyReported; - private static StatusCodeHttpResult? _status226IMUsed; - private static StatusCodeHttpResult? _status300MultipleChoices; - private static StatusCodeHttpResult? _status301MovedPermanently; - private static StatusCodeHttpResult? _status302Found; - private static StatusCodeHttpResult? _status303SeeOther; - private static StatusCodeHttpResult? _status304NotModified; - private static StatusCodeHttpResult? _status305UseProxy; - private static StatusCodeHttpResult? _status306SwitchProxy; - private static StatusCodeHttpResult? _status307TemporaryRedirect; - private static StatusCodeHttpResult? _status308PermanentRedirect; - private static StatusCodeHttpResult? _status400BadRequest; - private static StatusCodeHttpResult? _status401Unauthorized; - private static StatusCodeHttpResult? _status402PaymentRequired; - private static StatusCodeHttpResult? _status403Forbidden; - private static StatusCodeHttpResult? _status404NotFound; - private static StatusCodeHttpResult? _status405MethodNotAllowed; - private static StatusCodeHttpResult? _status406NotAcceptable; - private static StatusCodeHttpResult? _status407ProxyAuthenticationRequired; - private static StatusCodeHttpResult? _status408RequestTimeout; - private static StatusCodeHttpResult? _status409Conflict; - private static StatusCodeHttpResult? _status410Gone; - private static StatusCodeHttpResult? _status411LengthRequired; - private static StatusCodeHttpResult? _status412PreconditionFailed; - private static StatusCodeHttpResult? _status413RequestEntityTooLarge; - private static StatusCodeHttpResult? _status414RequestUriTooLong; - private static StatusCodeHttpResult? _status415UnsupportedMediaType; - private static StatusCodeHttpResult? _status416RequestedRangeNotSatisfiable; - private static StatusCodeHttpResult? _status417ExpectationFailed; - private static StatusCodeHttpResult? _status418ImATeapot; - private static StatusCodeHttpResult? _status419AuthenticationTimeout; - private static StatusCodeHttpResult? _status421MisdirectedRequest; - private static StatusCodeHttpResult? _status422UnprocessableEntity; - private static StatusCodeHttpResult? _status423Locked; - private static StatusCodeHttpResult? _status424FailedDependency; - private static StatusCodeHttpResult? _status426UpgradeRequired; - private static StatusCodeHttpResult? _status428PreconditionRequired; - private static StatusCodeHttpResult? _status429TooManyRequests; - private static StatusCodeHttpResult? _status431RequestHeaderFieldsTooLarge; - private static StatusCodeHttpResult? _status451UnavailableForLegalReasons; - private static StatusCodeHttpResult? _status500InternalServerError; - private static StatusCodeHttpResult? _status501NotImplemented; - private static StatusCodeHttpResult? _status502BadGateway; - private static StatusCodeHttpResult? _status503ServiceUnavailable; - private static StatusCodeHttpResult? _status504GatewayTimeout; - private static StatusCodeHttpResult? _status505HttpVersionNotsupported; - private static StatusCodeHttpResult? _status506VariantAlsoNegotiates; - private static StatusCodeHttpResult? _status507InsufficientStorage; - private static StatusCodeHttpResult? _status508LoopDetected; - private static StatusCodeHttpResult? _status510NotExtended; - private static StatusCodeHttpResult? _status511NetworkAuthenticationRequired; + private static Status? _status101SwitchingProtocols; + private static Status? _status102Processing; + private static Status? _status200OK; + private static Status? _status201Created; + private static Status? _status202Accepted; + private static Status? _status203NonAuthoritative; + private static Status? _status204NoContent; + private static Status? _status205ResetContent; + private static Status? _status206PartialContent; + private static Status? _status207MultiStatus; + private static Status? _status208AlreadyReported; + private static Status? _status226IMUsed; + private static Status? _status300MultipleChoices; + private static Status? _status301MovedPermanently; + private static Status? _status302Found; + private static Status? _status303SeeOther; + private static Status? _status304NotModified; + private static Status? _status305UseProxy; + private static Status? _status306SwitchProxy; + private static Status? _status307TemporaryRedirect; + private static Status? _status308PermanentRedirect; + private static Status? _status400BadRequest; + private static Status? _status401Unauthorized; + private static Status? _status402PaymentRequired; + private static Status? _status403Forbidden; + private static Status? _status404NotFound; + private static Status? _status405MethodNotAllowed; + private static Status? _status406NotAcceptable; + private static Status? _status407ProxyAuthenticationRequired; + private static Status? _status408RequestTimeout; + private static Status? _status409Conflict; + private static Status? _status410Gone; + private static Status? _status411LengthRequired; + private static Status? _status412PreconditionFailed; + private static Status? _status413RequestEntityTooLarge; + private static Status? _status414RequestUriTooLong; + private static Status? _status415UnsupportedMediaType; + private static Status? _status416RequestedRangeNotSatisfiable; + private static Status? _status417ExpectationFailed; + private static Status? _status418ImATeapot; + private static Status? _status419AuthenticationTimeout; + private static Status? _status421MisdirectedRequest; + private static Status? _status422UnprocessableEntity; + private static Status? _status423Locked; + private static Status? _status424FailedDependency; + private static Status? _status426UpgradeRequired; + private static Status? _status428PreconditionRequired; + private static Status? _status429TooManyRequests; + private static Status? _status431RequestHeaderFieldsTooLarge; + private static Status? _status451UnavailableForLegalReasons; + private static Status? _status500InternalServerError; + private static Status? _status501NotImplemented; + private static Status? _status502BadGateway; + private static Status? _status503ServiceUnavailable; + private static Status? _status504GatewayTimeout; + private static Status? _status505HttpVersionNotsupported; + private static Status? _status506VariantAlsoNegotiates; + private static Status? _status507InsufficientStorage; + private static Status? _status508LoopDetected; + private static Status? _status510NotExtended; + private static Status? _status511NetworkAuthenticationRequired; - internal static StatusCodeHttpResult StatusCode(int statusCode) + internal static Status StatusCode(int statusCode) { if (statusCode is (< 100) or (> 599)) { // No HTTP status code assigned outside the 100..599 range // so, it will not be available in the cache - return new StatusCodeHttpResult(statusCode); + return new Status(statusCode); } return statusCode switch @@ -145,7 +146,7 @@ internal static StatusCodeHttpResult StatusCode(int statusCode) StatusCodes.Status508LoopDetected => _status508LoopDetected ??= new(StatusCodes.Status508LoopDetected), StatusCodes.Status510NotExtended => _status510NotExtended ??= new(StatusCodes.Status510NotExtended), StatusCodes.Status511NetworkAuthenticationRequired => _status511NetworkAuthenticationRequired ??= new(StatusCodes.Status511NetworkAuthenticationRequired), - _ => new StatusCodeHttpResult(statusCode), + _ => new Status(statusCode), }; } } diff --git a/src/Http/Http.Results/src/ResultsCache.StatusCodes.tt b/src/Http/Http.Results/src/ResultsCache.StatusCodes.tt index 578deef36952..3b593cf822d4 100644 --- a/src/Http/Http.Results/src/ResultsCache.StatusCodes.tt +++ b/src/Http/Http.Results/src/ResultsCache.StatusCodes.tt @@ -76,6 +76,7 @@ #nullable enable using System.CodeDom.Compiler; +using Microsoft.AspNetCore.Http.HttpResults; namespace Microsoft.AspNetCore.Http; @@ -83,16 +84,16 @@ namespace Microsoft.AspNetCore.Http; internal partial class ResultsCache { <# foreach (var statusCode in statusCodes) { #> - private static StatusCodeHttpResult? _status<#= statusCode.Name #>; + private static Status? _status<#= statusCode.Name #>; <# } #> - internal static StatusCodeHttpResult StatusCode(int statusCode) + internal static Status StatusCode(int statusCode) { if (statusCode is (< 100) or (> 599)) { // No HTTP status code assigned outside the 100..599 range // so, it will not be available in the cache - return new StatusCodeHttpResult(statusCode); + return new Status(statusCode); } return statusCode switch @@ -100,7 +101,7 @@ internal partial class ResultsCache <# foreach (var statusCode in statusCodes) { #> StatusCodes.Status<#= statusCode.Name #> => _status<#= statusCode.Name #> ??= new(StatusCodes.Status<#= statusCode.Name #>), <# } #> - _ => new StatusCodeHttpResult(statusCode), + _ => new Status(statusCode), }; } } diff --git a/src/Http/Http.Results/src/ResultsCache.cs b/src/Http/Http.Results/src/ResultsCache.cs index dcdcaf092fb0..2caee1aff91b 100644 --- a/src/Http/Http.Results/src/ResultsCache.cs +++ b/src/Http/Http.Results/src/ResultsCache.cs @@ -1,15 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.AspNetCore.Http.HttpResults; + namespace Microsoft.AspNetCore.Http; internal static partial class ResultsCache { - public static NotFoundObjectHttpResult NotFound { get; } = new(null); - public static UnauthorizedHttpResult Unauthorized { get; } = new(); - public static BadRequestObjectHttpResult BadRequest { get; } = new(null); - public static ConflictObjectHttpResult Conflict { get; } = new(null); - public static NoContentHttpResult NoContent { get; } = new(); - public static OkObjectHttpResult Ok { get; } = new(null); - public static UnprocessableEntityObjectHttpResult UnprocessableEntity { get; } = new(null); + public static NotFound NotFound { get; } = new(); + public static Unauthorized Unauthorized { get; } = new(); + public static BadRequest BadRequest { get; } = new(); + public static Conflict Conflict { get; } = new(); + public static NoContent NoContent { get; } = new(); + public static Ok Ok { get; } = new(); + public static UnprocessableEntity UnprocessableEntity { get; } = new(); } diff --git a/src/Http/Http.Results/src/TypedResults.cs b/src/Http/Http.Results/src/TypedResults.cs index f219bbcf9048..ee5b4b300904 100644 --- a/src/Http/Http.Results/src/TypedResults.cs +++ b/src/Http/Http.Results/src/TypedResults.cs @@ -518,13 +518,13 @@ public static RedirectToRoute RedirectToRoute(string? routeName = null, object? /// The status code to set on the response. /// The created object for the response. public static Status StatusCode(int statusCode) - => new(statusCode); + => ResultsCache.StatusCode(statusCode); /// /// Produces a response. /// /// The created for the response. - public static NotFound NotFound() => new(); + public static NotFound NotFound() => ResultsCache.NotFound; /// /// Produces a response. @@ -537,13 +537,13 @@ public static Status StatusCode(int statusCode) /// Produces a response. /// /// The created for the response. - public static Unauthorized Unauthorized() => new(); + public static Unauthorized Unauthorized() => ResultsCache.Unauthorized; /// /// Produces a response. /// /// The created for the response. - public static BadRequest BadRequest() => new(); + public static BadRequest BadRequest() => ResultsCache.BadRequest; /// /// Produces a response. @@ -556,7 +556,7 @@ public static Status StatusCode(int statusCode) /// Produces a response. /// /// The created for the response. - public static Conflict Conflict() => new(); + public static Conflict Conflict() => ResultsCache.Conflict; /// /// Produces a response. @@ -569,13 +569,13 @@ public static Status StatusCode(int statusCode) /// Produces a response. /// /// The created for the response. - public static NoContent NoContent() => new(); + public static NoContent NoContent() => ResultsCache.NoContent; /// /// Produces a response. /// /// The created for the response. - public static Ok Ok() => new(); + public static Ok Ok() => ResultsCache.Ok; /// /// Produces a response. @@ -588,7 +588,7 @@ public static Status StatusCode(int statusCode) /// Produces a response. /// /// The created for the response. - public static UnprocessableEntity UnprocessableEntity() => new(); + public static UnprocessableEntity UnprocessableEntity() => ResultsCache.UnprocessableEntity; /// /// Produces a response. From 95c7f934e43771bc3a29d35c53f3d8ddc9556d31 Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Fri, 8 Apr 2022 16:21:45 -0700 Subject: [PATCH 04/35] Fixing unit tests --- .../test/BadRequestOfTResultTests.cs | 22 +++++ ...eResultTest.cs => ChallengeResultTests.cs} | 2 +- ...esultTest.cs => ConflictOfTResultTests.cs} | 2 +- ...ctResultTest.cs => ConflictResultTests.cs} | 2 +- ...entResultTest.cs => ContentResultTests.cs} | 2 +- ...EmptyResultTest.cs => EmptyResultTests.cs} | 2 +- ...esultTest.cs => FileContentResultTests.cs} | 2 +- ...rbidResultTest.cs => ForbidResultTests.cs} | 2 +- ...ltTest.cs => HttpFileStreamResultTests.cs} | 10 +-- ...bjectResultTests.cs => JsonResultTests.cs} | 86 ++++++++++++------- ...ultTest.cs => LocalRedirectResultTests.cs} | 2 +- ...esultTest.cs => NotFoundOfTResultTests.cs} | 10 +-- .../Http.Results/test/NotFoundResultTests.cs | 51 +++++++++++ ...bjectResultTest.cs => OkOfTResultTests.cs} | 40 +++++---- src/Http/Http.Results/test/OkResultTests.cs | 46 ++++++++++ ...ResultTest.cs => PushStreamResultTests.cs} | 2 +- ...ctResultTest.cs => RedirectResultTests.cs} | 2 +- ...tTest.cs => RedirectToRouteResultTests.cs} | 2 +- .../test/ResultsOfTTests.Generated.cs | 20 ++--- ...gnInResultTest.cs => SignInResultTests.cs} | 2 +- ...OutResultTest.cs => SignOutResultTests.cs} | 2 +- .../test/StatusCodeResultTests.cs | 2 +- ...s => UnprocessableEntityOfTResultTests.cs} | 10 +-- .../test/UnprocessableEntityResultTests.cs | 46 ++++++++++ ...esultTest.cs => VirtualFileResultTests.cs} | 2 +- .../tools/ResultsOfTGenerator/Program.cs | 13 +-- 26 files changed, 288 insertions(+), 96 deletions(-) rename src/Http/Http.Results/test/{ChallengeResultTest.cs => ChallengeResultTests.cs} (98%) rename src/Http/Http.Results/test/{ConflictOfTResultTest.cs => ConflictOfTResultTests.cs} (98%) rename src/Http/Http.Results/test/{ConflictResultTest.cs => ConflictResultTests.cs} (97%) rename src/Http/Http.Results/test/{ContentResultTest.cs => ContentResultTests.cs} (99%) rename src/Http/Http.Results/test/{EmptyResultTest.cs => EmptyResultTests.cs} (97%) rename src/Http/Http.Results/test/{FileContentResultTest.cs => FileContentResultTests.cs} (94%) rename src/Http/Http.Results/test/{ForbidResultTest.cs => ForbidResultTests.cs} (99%) rename src/Http/Http.Results/test/{FileStreamResultTest.cs => HttpFileStreamResultTests.cs} (85%) rename src/Http/Http.Results/test/{ObjectResultTests.cs => JsonResultTests.cs} (70%) rename src/Http/Http.Results/test/{LocalRedirectResultTest.cs => LocalRedirectResultTests.cs} (99%) rename src/Http/Http.Results/test/{NotFoundObjectResultTest.cs => NotFoundOfTResultTests.cs} (88%) create mode 100644 src/Http/Http.Results/test/NotFoundResultTests.cs rename src/Http/Http.Results/test/{OkObjectResultTest.cs => OkOfTResultTests.cs} (71%) create mode 100644 src/Http/Http.Results/test/OkResultTests.cs rename src/Http/Http.Results/test/{PushStreamResultTest.cs => PushStreamResultTests.cs} (98%) rename src/Http/Http.Results/test/{RedirectResultTest.cs => RedirectResultTests.cs} (93%) rename src/Http/Http.Results/test/{RedirectToRouteResultTest.cs => RedirectToRouteResultTests.cs} (98%) rename src/Http/Http.Results/test/{SignInResultTest.cs => SignInResultTests.cs} (98%) rename src/Http/Http.Results/test/{SignOutResultTest.cs => SignOutResultTests.cs} (98%) rename src/Http/Http.Results/test/{UnprocessableEntityObjectResultTests.cs => UnprocessableEntityOfTResultTests.cs} (87%) create mode 100644 src/Http/Http.Results/test/UnprocessableEntityResultTests.cs rename src/Http/Http.Results/test/{VirtualFileResultTest.cs => VirtualFileResultTests.cs} (92%) diff --git a/src/Http/Http.Results/test/BadRequestOfTResultTests.cs b/src/Http/Http.Results/test/BadRequestOfTResultTests.cs index b3f963028016..ef0b6b088ce6 100644 --- a/src/Http/Http.Results/test/BadRequestOfTResultTests.cs +++ b/src/Http/Http.Results/test/BadRequestOfTResultTests.cs @@ -4,6 +4,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using System.Text; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -74,6 +75,27 @@ public async Task BadRequestObjectResult_ExecuteResultAsync_FormatsData() Assert.Equal("\"Hello\"", Encoding.UTF8.GetString(stream.ToArray())); } + [Fact] + public async Task BadRequestObjectResult_ExecuteResultAsync_UsesStatusCodeFromResultTypeForProblemDetails() + { + // Arrange + var details = new ProblemDetails { Status = StatusCodes.Status422UnprocessableEntity, }; + var result = new BadRequest(details); + + var httpContext = new DefaultHttpContext() + { + RequestServices = CreateServices(), + }; + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status422UnprocessableEntity, details.Status.Value); + Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); + } + private static IServiceProvider CreateServices() { var services = new ServiceCollection(); diff --git a/src/Http/Http.Results/test/ChallengeResultTest.cs b/src/Http/Http.Results/test/ChallengeResultTests.cs similarity index 98% rename from src/Http/Http.Results/test/ChallengeResultTest.cs rename to src/Http/Http.Results/test/ChallengeResultTests.cs index 2e49139758ac..c1da91476a72 100644 --- a/src/Http/Http.Results/test/ChallengeResultTest.cs +++ b/src/Http/Http.Results/test/ChallengeResultTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class ChallengeResultTest +public class ChallengeResultTests { [Fact] public async Task ChallengeResult_ExecuteAsync() diff --git a/src/Http/Http.Results/test/ConflictOfTResultTest.cs b/src/Http/Http.Results/test/ConflictOfTResultTests.cs similarity index 98% rename from src/Http/Http.Results/test/ConflictOfTResultTest.cs rename to src/Http/Http.Results/test/ConflictOfTResultTests.cs index c5454408ec59..7fa3387520a4 100644 --- a/src/Http/Http.Results/test/ConflictOfTResultTest.cs +++ b/src/Http/Http.Results/test/ConflictOfTResultTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -public class ConflictOfTResultTest +public class ConflictOfTResultTests { [Fact] public void ConflictObjectResult_SetsStatusCodeAndValue() diff --git a/src/Http/Http.Results/test/ConflictResultTest.cs b/src/Http/Http.Results/test/ConflictResultTests.cs similarity index 97% rename from src/Http/Http.Results/test/ConflictResultTest.cs rename to src/Http/Http.Results/test/ConflictResultTests.cs index 7c53821d55e8..8b1420c23a29 100644 --- a/src/Http/Http.Results/test/ConflictResultTest.cs +++ b/src/Http/Http.Results/test/ConflictResultTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -public class ConflictResultTest +public class ConflictResultTests { [Fact] public void ConflictObjectResult_SetsStatusCode() diff --git a/src/Http/Http.Results/test/ContentResultTest.cs b/src/Http/Http.Results/test/ContentResultTests.cs similarity index 99% rename from src/Http/Http.Results/test/ContentResultTest.cs rename to src/Http/Http.Results/test/ContentResultTests.cs index 276e234cbed9..8a3f742d7eb5 100644 --- a/src/Http/Http.Results/test/ContentResultTest.cs +++ b/src/Http/Http.Results/test/ContentResultTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class ContentResultTest +public class ContentResultTests { [Fact] public async Task ContentResult_ExecuteAsync_Response_NullContent_SetsContentTypeAndEncoding() diff --git a/src/Http/Http.Results/test/EmptyResultTest.cs b/src/Http/Http.Results/test/EmptyResultTests.cs similarity index 97% rename from src/Http/Http.Results/test/EmptyResultTest.cs rename to src/Http/Http.Results/test/EmptyResultTests.cs index 74eb8ae20a01..44ac64bee281 100644 --- a/src/Http/Http.Results/test/EmptyResultTest.cs +++ b/src/Http/Http.Results/test/EmptyResultTests.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class EmptyResultTest +public class EmptyResultTests { [Fact] public async Task EmptyResult_DoesNothing() diff --git a/src/Http/Http.Results/test/FileContentResultTest.cs b/src/Http/Http.Results/test/FileContentResultTests.cs similarity index 94% rename from src/Http/Http.Results/test/FileContentResultTest.cs rename to src/Http/Http.Results/test/FileContentResultTests.cs index 8f8ce8eb5f0c..15d746f1f912 100644 --- a/src/Http/Http.Results/test/FileContentResultTest.cs +++ b/src/Http/Http.Results/test/FileContentResultTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class FileContentResultTest : FileContentResultTestBase +public class FileContentResultTests : FileContentResultTestBase { protected override Task ExecuteAsync( HttpContext httpContext, diff --git a/src/Http/Http.Results/test/ForbidResultTest.cs b/src/Http/Http.Results/test/ForbidResultTests.cs similarity index 99% rename from src/Http/Http.Results/test/ForbidResultTest.cs rename to src/Http/Http.Results/test/ForbidResultTests.cs index be360a39847f..d4d5ee15cf97 100644 --- a/src/Http/Http.Results/test/ForbidResultTest.cs +++ b/src/Http/Http.Results/test/ForbidResultTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class ForbidResultTest +public class ForbidResultTests { [Fact] public async Task ExecuteResultAsync_InvokesForbidAsyncOnAuthenticationService() diff --git a/src/Http/Http.Results/test/FileStreamResultTest.cs b/src/Http/Http.Results/test/HttpFileStreamResultTests.cs similarity index 85% rename from src/Http/Http.Results/test/FileStreamResultTest.cs rename to src/Http/Http.Results/test/HttpFileStreamResultTests.cs index 286950535534..fd9d60b9e121 100644 --- a/src/Http/Http.Results/test/FileStreamResultTest.cs +++ b/src/Http/Http.Results/test/HttpFileStreamResultTests.cs @@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class FileStreamResultTest : FileStreamResultTestBase +public class HttpFileStreamResultTests : FileStreamResultTestBase { protected override Task ExecuteAsync( HttpContext httpContext, @@ -16,7 +16,7 @@ protected override Task ExecuteAsync( EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { - var fileStreamResult = new FileStream(stream, contentType) + var fileStreamResult = new HttpFileStream(stream, contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -33,7 +33,7 @@ public void Constructor_SetsFileName() var stream = Stream.Null; // Act - var result = new FileStream(stream, "text/plain"); + var result = new HttpFileStream(stream, "text/plain"); // Assert Assert.Equal(stream, result.FileStream); @@ -48,7 +48,7 @@ public void Constructor_SetsContentTypeAndParameters() var expectedMediaType = contentType; // Act - var result = new FileStream(stream, contentType); + var result = new HttpFileStream(stream, contentType); // Assert Assert.Equal(stream, result.FileStream); @@ -66,7 +66,7 @@ public void Constructor_SetsLastModifiedAndEtag() var entityTag = new EntityTagHeaderValue("\"Etag\""); // Act - var result = new FileStream(stream, contentType) + var result = new HttpFileStream(stream, contentType) { LastModified = lastModified, EntityTag = entityTag, diff --git a/src/Http/Http.Results/test/ObjectResultTests.cs b/src/Http/Http.Results/test/JsonResultTests.cs similarity index 70% rename from src/Http/Http.Results/test/ObjectResultTests.cs rename to src/Http/Http.Results/test/JsonResultTests.cs index 1a25ea2b7485..ef82c68393cb 100644 --- a/src/Http/Http.Results/test/ObjectResultTests.cs +++ b/src/Http/Http.Results/test/JsonResultTests.cs @@ -10,13 +10,13 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class ObjectResultTests +public class JsonResultTests { [Fact] - public async Task ObjectResult_ExecuteAsync_WithNullValue_Works() + public async Task JsonResult_ExecuteAsync_WithNullValue_Works() { // Arrange - var result = new ObjectHttpResult(value: null, 411); + var result = new Json(value: null, statusCode: 411, jsonSerializerOptions: null); var httpContext = new DefaultHttpContext() { @@ -31,10 +31,10 @@ public async Task ObjectResult_ExecuteAsync_WithNullValue_Works() } [Fact] - public async Task ObjectResult_ExecuteAsync_SetsStatusCode() + public async Task JsonResult_ExecuteAsync_SetsStatusCode() { // Arrange - var result = new ObjectHttpResult("Hello", 407); + var result = new Json(value: null, statusCode: 407, jsonSerializerOptions: null); var httpContext = new DefaultHttpContext() { @@ -49,10 +49,10 @@ public async Task ObjectResult_ExecuteAsync_SetsStatusCode() } [Fact] - public async Task ObjectResult_ExecuteAsync_JsonSerializesBody() + public async Task JsonResult_ExecuteAsync_JsonSerializesBody() { // Arrange - var result = new ObjectHttpResult("Hello", 407); + var result = new Json(value: null, statusCode: 407, jsonSerializerOptions: null); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -70,13 +70,50 @@ public async Task ObjectResult_ExecuteAsync_JsonSerializesBody() Assert.Equal("\"Hello\"", Encoding.UTF8.GetString(stream.ToArray())); } + [Fact] + public async Task JsonResult_ExecuteAsync_JsonSerializesBody_WitOptions() + { + // Arrange + var jsonOptions = new JsonSerializerOptions() + { + WriteIndented = true, + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull + }; + var value = new Todo(10, "MyName") { Description = null }; + var result = new Json(value, jsonSerializerOptions: jsonOptions); + var stream = new MemoryStream(); + var httpContext = new DefaultHttpContext() + { + RequestServices = CreateServices(), + Response = + { + Body = stream, + }, + }; + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status200OK, httpContext.Response.StatusCode); + + stream.Position = 0; + var responseDetails = JsonSerializer.Deserialize(stream); + Assert.Equal(value.Id, responseDetails.Id); + Assert.Equal(value.Title, responseDetails.Title); + Assert.Equal(value.Description, responseDetails.Description); + + stream.Position = 0; + Assert.Equal(JsonSerializer.Serialize(value, options: jsonOptions), Encoding.UTF8.GetString(stream.ToArray())); + } + [Fact] public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() { // Arrange var details = new ProblemDetails(); - var result = new ObjectHttpResult(details); + var result = new Json(details, jsonSerializerOptions: null); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -105,7 +142,7 @@ public async Task ExecuteAsync_UsesDefaults_ForValidationProblemDetails() // Arrange var details = new HttpValidationProblemDetails(); - var result = new ObjectHttpResult(details); + var result = new Json(details, jsonSerializerOptions: null); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -134,7 +171,7 @@ public async Task ExecuteAsync_SetsProblemDetailsStatus_ForValidationProblemDeta // Arrange var details = new HttpValidationProblemDetails(); - var result = new ObjectHttpResult(details, StatusCodes.Status422UnprocessableEntity); + var result = new Json(details, StatusCodes.Status422UnprocessableEntity, jsonSerializerOptions: null); var httpContext = new DefaultHttpContext() { RequestServices = CreateServices(), @@ -153,7 +190,7 @@ public async Task ExecuteAsync_GetsStatusCodeFromProblemDetails() // Arrange var details = new ProblemDetails { Status = StatusCodes.Status413RequestEntityTooLarge, }; - var result = new ObjectHttpResult(details); + var result = new Json(details, jsonSerializerOptions: null); var httpContext = new DefaultHttpContext() { @@ -169,28 +206,6 @@ public async Task ExecuteAsync_GetsStatusCodeFromProblemDetails() Assert.Equal(StatusCodes.Status413RequestEntityTooLarge, httpContext.Response.StatusCode); } - [Fact] - public async Task ExecuteAsync_UsesStatusCodeFromResultTypeForProblemDetails() - { - // Arrange - var details = new ProblemDetails { Status = StatusCodes.Status422UnprocessableEntity, }; - - var result = new BadRequest(details); - - var httpContext = new DefaultHttpContext() - { - RequestServices = CreateServices(), - }; - - // Act - await result.ExecuteAsync(httpContext); - - // Assert - Assert.Equal(StatusCodes.Status422UnprocessableEntity, details.Status.Value); - Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); - Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); - } - private static IServiceProvider CreateServices() { var services = new ServiceCollection(); @@ -198,4 +213,9 @@ private static IServiceProvider CreateServices() return services.BuildServiceProvider(); } + + private record Todo(int Id, string Title) + { + public string Description { get; init; } + } } diff --git a/src/Http/Http.Results/test/LocalRedirectResultTest.cs b/src/Http/Http.Results/test/LocalRedirectResultTests.cs similarity index 99% rename from src/Http/Http.Results/test/LocalRedirectResultTest.cs rename to src/Http/Http.Results/test/LocalRedirectResultTests.cs index fe90f1566aec..42372d821e5c 100644 --- a/src/Http/Http.Results/test/LocalRedirectResultTest.cs +++ b/src/Http/Http.Results/test/LocalRedirectResultTests.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class LocalRedirectResultTest +public class LocalRedirectResultTests { [Fact] public void Constructor_WithParameterUrl_SetsResultUrlAndNotPermanentOrPreserveMethod() diff --git a/src/Http/Http.Results/test/NotFoundObjectResultTest.cs b/src/Http/Http.Results/test/NotFoundOfTResultTests.cs similarity index 88% rename from src/Http/Http.Results/test/NotFoundObjectResultTest.cs rename to src/Http/Http.Results/test/NotFoundOfTResultTests.cs index 164bad32b62e..90b5d34590d7 100644 --- a/src/Http/Http.Results/test/NotFoundObjectResultTest.cs +++ b/src/Http/Http.Results/test/NotFoundOfTResultTests.cs @@ -7,14 +7,14 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class NotFoundObjectResultTest +public class NotFoundOfTResultTests { [Fact] public void NotFoundObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new HttpValidationProblemDetails(); - var result = new NotFound(obj); + var result = new NotFound(obj); // Assert Assert.Equal(StatusCodes.Status404NotFound, result.StatusCode); @@ -26,7 +26,7 @@ public void NotFoundObjectResult_ProblemDetails_SetsStatusCodeAndValue() public void NotFoundObjectResult_InitializesStatusCode() { // Arrange & act - var notFound = new NotFound(null); + var notFound = new NotFound(null); // Assert Assert.Equal(StatusCodes.Status404NotFound, notFound.StatusCode); @@ -36,7 +36,7 @@ public void NotFoundObjectResult_InitializesStatusCode() public void NotFoundObjectResult_InitializesStatusCodeAndResponseContent() { // Arrange & act - var notFound = new NotFound("Test Content"); + var notFound = new NotFound("Test Content"); // Assert Assert.Equal(StatusCodes.Status404NotFound, notFound.StatusCode); @@ -48,7 +48,7 @@ public async Task NotFoundObjectResult_ExecuteSuccessful() { // Arrange var httpContext = GetHttpContext(); - var result = new NotFound("Test Content"); + var result = new NotFound("Test Content"); // Act await result.ExecuteAsync(httpContext); diff --git a/src/Http/Http.Results/test/NotFoundResultTests.cs b/src/Http/Http.Results/test/NotFoundResultTests.cs new file mode 100644 index 000000000000..e61a0b78b858 --- /dev/null +++ b/src/Http/Http.Results/test/NotFoundResultTests.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +public class NotFoundResultTests +{ + [Fact] + public void NotFoundObjectResult_InitializesStatusCode() + { + // Arrange & act + var notFound = new NotFound(); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, notFound.StatusCode); + } + + [Fact] + public async Task NotFoundObjectResult_ExecuteSuccessful() + { + // Arrange + var httpContext = GetHttpContext(); + var result = new NotFound(); + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, httpContext.Response.StatusCode); + } + + private static HttpContext GetHttpContext() + { + var httpContext = new DefaultHttpContext(); + httpContext.Request.PathBase = new PathString(""); + httpContext.Response.Body = new MemoryStream(); + httpContext.RequestServices = CreateServices(); + return httpContext; + } + + private static IServiceProvider CreateServices() + { + var services = new ServiceCollection(); + services.AddSingleton(); + return services.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Results/test/OkObjectResultTest.cs b/src/Http/Http.Results/test/OkOfTResultTests.cs similarity index 71% rename from src/Http/Http.Results/test/OkObjectResultTest.cs rename to src/Http/Http.Results/test/OkOfTResultTests.cs index ab0aa1782339..157316008eeb 100644 --- a/src/Http/Http.Results/test/OkObjectResultTest.cs +++ b/src/Http/Http.Results/test/OkOfTResultTests.cs @@ -8,20 +8,18 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class OkObjectResultTest +public class OkOfTResultTests { [Fact] - public async Task OkObjectResult_SetsStatusCodeAndValue() + public void OkObjectResult_SetsStatusCodeAndValue() { - // Arrange - var result = new Ok("Hello world"); - var httpContext = GetHttpContext(); - - // Act - await result.ExecuteAsync(httpContext); + // Arrange & Act + var value = "Hello world"; + var result = new Ok(value); // Assert - Assert.Equal(StatusCodes.Status200OK, httpContext.Response.StatusCode); + Assert.Equal(StatusCodes.Status200OK, result.StatusCode); + Assert.Equal(value, result.Value); } [Fact] @@ -29,7 +27,7 @@ public void OkObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new HttpValidationProblemDetails(); - var result = new Ok(obj); + var result = new Ok(obj); // Assert Assert.Equal(StatusCodes.Status200OK, result.StatusCode); @@ -41,7 +39,7 @@ public void OkObjectResult_ProblemDetails_SetsStatusCodeAndValue() public async Task OkObjectResult_ExecuteAsync_FormatsData() { // Arrange - var result = new Ok("Hello"); + var result = new Ok("Hello"); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -59,13 +57,21 @@ public async Task OkObjectResult_ExecuteAsync_FormatsData() Assert.Equal("\"Hello\"", Encoding.UTF8.GetString(stream.ToArray())); } - private static HttpContext GetHttpContext() + [Fact] + public async Task OkObjectResult_ExecuteAsync_SetsStatusCode() { - var httpContext = new DefaultHttpContext(); - httpContext.Request.PathBase = new PathString(""); - httpContext.Response.Body = new MemoryStream(); - httpContext.RequestServices = CreateServices(); - return httpContext; + // Arrange + var result = new Ok("Hello"); + var httpContext = new DefaultHttpContext() + { + RequestServices = CreateServices() + }; + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status200OK, httpContext.Response.StatusCode); } private static IServiceProvider CreateServices() diff --git a/src/Http/Http.Results/test/OkResultTests.cs b/src/Http/Http.Results/test/OkResultTests.cs new file mode 100644 index 000000000000..37cfd1a52b8d --- /dev/null +++ b/src/Http/Http.Results/test/OkResultTests.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +public class OkResultTests +{ + [Fact] + public void OkObjectResult_SetsStatusCodeAndValue() + { + // Arrange & Act + var result = new Ok(); + + // Assert + Assert.Equal(StatusCodes.Status200OK, result.StatusCode); + } + + [Fact] + public async Task OkObjectResult_ExecuteAsync_SetsStatusCode() + { + // Arrange + var result = new Ok(); + var httpContext = new DefaultHttpContext() + { + RequestServices = CreateServices() + }; + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status200OK, httpContext.Response.StatusCode); + } + + private static IServiceProvider CreateServices() + { + var services = new ServiceCollection(); + services.AddSingleton(); + return services.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Results/test/PushStreamResultTest.cs b/src/Http/Http.Results/test/PushStreamResultTests.cs similarity index 98% rename from src/Http/Http.Results/test/PushStreamResultTest.cs rename to src/Http/Http.Results/test/PushStreamResultTests.cs index 497b4f481c36..7460c6dc988d 100644 --- a/src/Http/Http.Results/test/PushStreamResultTest.cs +++ b/src/Http/Http.Results/test/PushStreamResultTests.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class PushStreamResultTest +public class PushStreamResultTests { [Fact] public async Task PushStreamResultsExposeTheResponseBody() diff --git a/src/Http/Http.Results/test/RedirectResultTest.cs b/src/Http/Http.Results/test/RedirectResultTests.cs similarity index 93% rename from src/Http/Http.Results/test/RedirectResultTest.cs rename to src/Http/Http.Results/test/RedirectResultTests.cs index 20e1bcc7b652..18632b675683 100644 --- a/src/Http/Http.Results/test/RedirectResultTest.cs +++ b/src/Http/Http.Results/test/RedirectResultTests.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class RedirectResultTest : RedirectResultTestBase +public class RedirectResultTests : RedirectResultTestBase { [Fact] public void RedirectResult_Constructor_WithParameterUrlPermanentAndPreservesMethod_SetsResultUrlPermanentAndPreservesMethod() diff --git a/src/Http/Http.Results/test/RedirectToRouteResultTest.cs b/src/Http/Http.Results/test/RedirectToRouteResultTests.cs similarity index 98% rename from src/Http/Http.Results/test/RedirectToRouteResultTest.cs rename to src/Http/Http.Results/test/RedirectToRouteResultTests.cs index b7a503f40bbc..b2e404893229 100644 --- a/src/Http/Http.Results/test/RedirectToRouteResultTest.cs +++ b/src/Http/Http.Results/test/RedirectToRouteResultTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class RedirectToRouteResultTest +public class RedirectToRouteResultTests { [Fact] public async Task RedirectToRoute_Execute_ThrowsOnNullUrl() diff --git a/src/Http/Http.Results/test/ResultsOfTTests.Generated.cs b/src/Http/Http.Results/test/ResultsOfTTests.Generated.cs index f950aca6aada..e776f41e5e6e 100644 --- a/src/Http/Http.Results/test/ResultsOfTTests.Generated.cs +++ b/src/Http/Http.Results/test/ResultsOfTTests.Generated.cs @@ -63,7 +63,7 @@ Results MyApi(int checksum) public void ResultsOfTResult1TResult2_Throws_ArgumentNullException_WhenHttpContextIsNull() { // Arrange - Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } @@ -82,7 +82,7 @@ Results MyApi() public void ResultsOfTResult1TResult2_Throws_InvalidOperationException_WhenResultIsNull() { // Arrange - Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } @@ -271,7 +271,7 @@ Results MyApi(int checksum) public void ResultsOfTResult1TResult2TResult3_Throws_ArgumentNullException_WhenHttpContextIsNull() { // Arrange - Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } @@ -290,7 +290,7 @@ Results MyApi() public void ResultsOfTResult1TResult2TResult3_Throws_InvalidOperationException_WhenResultIsNull() { // Arrange - Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } @@ -548,7 +548,7 @@ Results MyAp public void ResultsOfTResult1TResult2TResult3TResult4_Throws_ArgumentNullException_WhenHttpContextIsNull() { // Arrange - Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } @@ -567,7 +567,7 @@ Results MyApi() public void ResultsOfTResult1TResult2TResult3TResult4_Throws_InvalidOperationException_WhenResultIsNull() { // Arrange - Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } @@ -902,7 +902,7 @@ Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } @@ -921,7 +921,7 @@ Results MyApi() public void ResultsOfTResult1TResult2TResult3TResult4TResult5_Throws_InvalidOperationException_WhenResultIsNull() { // Arrange - Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } @@ -1341,7 +1341,7 @@ Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } @@ -1360,7 +1360,7 @@ Results MyApi() public void ResultsOfTResult1TResult2TResult3TResult4TResult5TResult6_Throws_InvalidOperationException_WhenResultIsNull() { // Arrange - Results MyApi() + Results MyApi() { return new ChecksumResult1(1); } diff --git a/src/Http/Http.Results/test/SignInResultTest.cs b/src/Http/Http.Results/test/SignInResultTests.cs similarity index 98% rename from src/Http/Http.Results/test/SignInResultTest.cs rename to src/Http/Http.Results/test/SignInResultTests.cs index 0c3c24274ace..268ebff1d0d5 100644 --- a/src/Http/Http.Results/test/SignInResultTest.cs +++ b/src/Http/Http.Results/test/SignInResultTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class SignInResultTest +public class SignInResultTests { [Fact] public async Task ExecuteAsync_InvokesSignInAsyncOnAuthenticationManager() diff --git a/src/Http/Http.Results/test/SignOutResultTest.cs b/src/Http/Http.Results/test/SignOutResultTests.cs similarity index 98% rename from src/Http/Http.Results/test/SignOutResultTest.cs rename to src/Http/Http.Results/test/SignOutResultTests.cs index 73438444def9..fd29c979e563 100644 --- a/src/Http/Http.Results/test/SignOutResultTest.cs +++ b/src/Http/Http.Results/test/SignOutResultTests.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class SignOutResultTest +public class SignOutResultTests { [Fact] public async Task ExecuteAsync_NoArgsInvokesDefaultSignOut() diff --git a/src/Http/Http.Results/test/StatusCodeResultTests.cs b/src/Http/Http.Results/test/StatusCodeResultTests.cs index 1c9afcf9fb64..631378619e0c 100644 --- a/src/Http/Http.Results/test/StatusCodeResultTests.cs +++ b/src/Http/Http.Results/test/StatusCodeResultTests.cs @@ -13,7 +13,7 @@ public class StatusCodeResultTests public void StatusCodeResult_ExecuteResultSetsResponseStatusCode() { // Arrange - var result = new StatusCode(StatusCodes.Status404NotFound); + var result = new Status(StatusCodes.Status404NotFound); var httpContext = GetHttpContext(); diff --git a/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs b/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs similarity index 87% rename from src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs rename to src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs index 0396b469ec8b..5003c83b6ff7 100644 --- a/src/Http/Http.Results/test/UnprocessableEntityObjectResultTests.cs +++ b/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs @@ -8,14 +8,14 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -public class UnprocessableEntityObjectResultTests +public class UnprocessableEntityOfTResultTests { [Fact] public void NotFoundObjectResult_ProblemDetails_SetsStatusCodeAndValue() { // Arrange & Act var obj = new HttpValidationProblemDetails(); - var result = new UnprocessableEntity(obj); + var result = new UnprocessableEntity(obj); // Assert Assert.Equal(StatusCodes.Status422UnprocessableEntity, result.StatusCode); @@ -28,7 +28,7 @@ public void UnprocessableEntityObjectResult_SetsStatusCodeAndValue() { // Arrange & Act var obj = new object(); - var result = new UnprocessableEntity(obj); + var result = new UnprocessableEntity(obj); // Assert Assert.Equal(StatusCodes.Status422UnprocessableEntity, result.StatusCode); @@ -39,7 +39,7 @@ public void UnprocessableEntityObjectResult_SetsStatusCodeAndValue() public async Task UnprocessableEntityObjectResult_ExecuteAsync_SetsStatusCode() { // Arrange - var result = new UnprocessableEntity("Hello"); + var result = new UnprocessableEntity("Hello"); var httpContext = new DefaultHttpContext() { RequestServices = CreateServices(), @@ -56,7 +56,7 @@ public async Task UnprocessableEntityObjectResult_ExecuteAsync_SetsStatusCode() public async Task UnprocessableEntityObjectResult_ExecuteResultAsync_FormatsData() { // Arrange - var result = new UnprocessableEntity("Hello"); + var result = new UnprocessableEntity("Hello"); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs b/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs new file mode 100644 index 000000000000..44075ada9574 --- /dev/null +++ b/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.HttpResults; + +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +public class UnprocessableEntityResultTests +{ + [Fact] + public void UnprocessableEntityObjectResult_SetsStatusCode() + { + // Arrange & Act + var result = new UnprocessableEntity(); + + // Assert + Assert.Equal(StatusCodes.Status422UnprocessableEntity, result.StatusCode); + } + + [Fact] + public async Task UnprocessableEntityObjectResult_ExecuteAsync_SetsStatusCode() + { + // Arrange + var result = new UnprocessableEntity(); + var httpContext = new DefaultHttpContext() + { + RequestServices = CreateServices(), + }; + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status422UnprocessableEntity, httpContext.Response.StatusCode); + } + + private static IServiceProvider CreateServices() + { + var services = new ServiceCollection(); + services.AddSingleton(); + return services.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Results/test/VirtualFileResultTest.cs b/src/Http/Http.Results/test/VirtualFileResultTests.cs similarity index 92% rename from src/Http/Http.Results/test/VirtualFileResultTest.cs rename to src/Http/Http.Results/test/VirtualFileResultTests.cs index 775afdabf1fb..9dcf525ec858 100644 --- a/src/Http/Http.Results/test/VirtualFileResultTest.cs +++ b/src/Http/Http.Results/test/VirtualFileResultTests.cs @@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; -public class VirtualFileResultTest : VirtualFileResultTestBase +public class VirtualFileResultTests : VirtualFileResultTestBase { protected override Task ExecuteAsync(HttpContext httpContext, string path, string contentType, DateTimeOffset? lastModified = null, EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { diff --git a/src/Http/Http.Results/tools/ResultsOfTGenerator/Program.cs b/src/Http/Http.Results/tools/ResultsOfTGenerator/Program.cs index 44fb25c7009a..6326fe6faca1 100644 --- a/src/Http/Http.Results/tools/ResultsOfTGenerator/Program.cs +++ b/src/Http/Http.Results/tools/ResultsOfTGenerator/Program.cs @@ -231,6 +231,7 @@ static void GenerateTestFiles(string testFilePath, int typeArgCount, bool intera writer.WriteLine("using System.Reflection;"); writer.WriteLine("using System.Threading.Tasks;"); writer.WriteLine("using Microsoft.AspNetCore.Http.Metadata;"); + writer.WriteLine("using Microsoft.AspNetCore.Http.HttpResults;"); writer.WriteLine("using Microsoft.Extensions.DependencyInjection;"); writer.WriteLine("using Microsoft.Extensions.Logging;"); writer.WriteLine("using Microsoft.Extensions.Logging.Abstractions;"); @@ -388,13 +389,13 @@ static void GenerateTest_ExecuteResult_ExecutesAssignedResult(StreamWriter write //public async Task ResultsOfTResult1TResult2_ExecuteResult_ExecutesAssignedResult(int input, object expected) //{ // // Arrange - // Results MyApi(int checksum) + // Results MyApi(int checksum) // { // return checksum switch // { // 1 => new ChecksumResult1(checksum), // 2 => new ChecksumResult2(checksum), - // _ => (NoContentHttpResult)Results.NoContent() + // _ => (NoContent)Results.NoContent() // }; // } // var httpContext = GetHttpContext(); @@ -478,7 +479,7 @@ static void GenerateTest_Throws_ArgumentNullException_WhenHttpContextIsNull(Stre //public void ResultsOfTResult1TResult2_Throws_ArgumentNullException_WhenHttpContextIsNull() //{ // // Arrange - // Results MyApi() + // Results MyApi() // { // return new ChecksumResult1(1); // } @@ -507,7 +508,7 @@ static void GenerateTest_Throws_ArgumentNullException_WhenHttpContextIsNull(Stre // Arrange writer.WriteIndentedLine(2, "// Arrange"); - writer.WriteIndentedLine(2, "Results MyApi()"); + writer.WriteIndentedLine(2, "Results MyApi()"); writer.WriteIndentedLine(2, "{"); writer.WriteIndentedLine(3, "return new ChecksumResult1(1);"); writer.WriteIndentedLine(2, "}"); @@ -535,7 +536,7 @@ static void GenerateTest_Throws_InvalidOperationException_WhenResultIsNull(Strea //public void ResultsOfTResult1TResult2_Throws_InvalidOperationException_WhenResultIsNull() //{ // // Arrange - // Results MyApi() + // Results MyApi() // { // return (ChecksumResult1)null; // } @@ -564,7 +565,7 @@ static void GenerateTest_Throws_InvalidOperationException_WhenResultIsNull(Strea // Arrange writer.WriteIndentedLine(2, "// Arrange"); - writer.WriteIndentedLine(2, "Results MyApi()"); + writer.WriteIndentedLine(2, "Results MyApi()"); writer.WriteIndentedLine(2, "{"); writer.WriteIndentedLine(3, "return new ChecksumResult1(1);"); writer.WriteIndentedLine(2, "}"); From 3d85d406bc76dcdb4b4202e213ceeebc9189c165 Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Fri, 8 Apr 2022 16:38:09 -0700 Subject: [PATCH 05/35] Fixing json result --- src/Http/Http.Results/src/Json.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Http/Http.Results/src/Json.cs b/src/Http/Http.Results/src/Json.cs index 98e6ac13b6fd..014cc4d7e4e6 100644 --- a/src/Http/Http.Results/src/Json.cs +++ b/src/Http/Http.Results/src/Json.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -55,10 +56,16 @@ internal Json(TValue? value, string? contentType, JsonSerializerOptions? jsonSer internal Json(TValue? value, int? statusCode, string? contentType, JsonSerializerOptions? jsonSerializerOptions) { Value = value; - StatusCode = statusCode; JsonSerializerOptions = jsonSerializerOptions; ContentType = contentType; - HttpResultsHelper.ApplyProblemDetailsDefaultsIfNeeded(Value, StatusCode); + + if (value is ProblemDetails problemDetails) + { + HttpResultsHelper.ApplyProblemDetailsDefaults(problemDetails, statusCode); + statusCode ??= problemDetails.Status; + } + + StatusCode = statusCode; } /// From a12c7439be15d1d456915ee5f09ad00dbe79b1de Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Fri, 8 Apr 2022 16:38:25 -0700 Subject: [PATCH 06/35] Fixing tests --- src/Http/Http.Results/test/JsonResultTests.cs | 2 +- src/Http/Http.Results/test/ResultsCacheTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Http/Http.Results/test/JsonResultTests.cs b/src/Http/Http.Results/test/JsonResultTests.cs index ef82c68393cb..263d8790b6c7 100644 --- a/src/Http/Http.Results/test/JsonResultTests.cs +++ b/src/Http/Http.Results/test/JsonResultTests.cs @@ -52,7 +52,7 @@ public async Task JsonResult_ExecuteAsync_SetsStatusCode() public async Task JsonResult_ExecuteAsync_JsonSerializesBody() { // Arrange - var result = new Json(value: null, statusCode: 407, jsonSerializerOptions: null); + var result = new Json(value: "Hello", statusCode: 407, jsonSerializerOptions: null); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/ResultsCacheTests.cs b/src/Http/Http.Results/test/ResultsCacheTests.cs index 15593f88fdea..f6b7a7ccc98e 100644 --- a/src/Http/Http.Results/test/ResultsCacheTests.cs +++ b/src/Http/Http.Results/test/ResultsCacheTests.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.Results.Tests; +namespace Microsoft.AspNetCore.Http.Results; using Mono.TextTemplating; From 8247fea1aec04ede677ef9f2aa11423a18e8b510 Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Fri, 8 Apr 2022 16:38:42 -0700 Subject: [PATCH 07/35] Updating sample --- src/Http/samples/MinimalSample/Program.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Http/samples/MinimalSample/Program.cs b/src/Http/samples/MinimalSample/Program.cs index 1b9b249a1d57..38edc7422b6b 100644 --- a/src/Http/samples/MinimalSample/Program.cs +++ b/src/Http/samples/MinimalSample/Program.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; var app = WebApplication.Create(args); @@ -21,12 +22,12 @@ app.MapGet("/null-result", IResult () => null); -app.MapGet("/todo/{id}", Results (int id) => +app.MapGet("/todo/{id}", Results, NotFound> (int id) => { return id switch { - >= 1 and <= 10 => (OkObjectHttpResult)Results.Ok(new { Id = id, Title = "Walk the dog" }), - _ => (NotFoundObjectHttpResult)Results.NotFound() + >= 1 and <= 10 => Results.Typed.Ok(new Todo(id, "Walk the dog")), + _ => Results.Typed.NotFound() }; }); @@ -47,3 +48,5 @@ Results.Problem(new HttpValidationProblemDetails(errors) { Status = 400, Extensions = { { "traceId", "traceId123" } } })); app.Run(); + +internal record Todo(int Id, string Title); From 008b8e15036a9ed4ee0177ea833eb65e45214e6c Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Fri, 8 Apr 2022 16:42:26 -0700 Subject: [PATCH 08/35] Updating sample --- src/Http/samples/MinimalSample/Program.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Http/samples/MinimalSample/Program.cs b/src/Http/samples/MinimalSample/Program.cs index 38edc7422b6b..1324f8ab8fa2 100644 --- a/src/Http/samples/MinimalSample/Program.cs +++ b/src/Http/samples/MinimalSample/Program.cs @@ -22,14 +22,12 @@ app.MapGet("/null-result", IResult () => null); -app.MapGet("/todo/{id}", Results, NotFound> (int id) => -{ - return id switch +app.MapGet("/todo/{id}", Results, NotFound, BadRequest> (int id) => id switch { + <= 0 => Results.Typed.BadRequest(), >= 1 and <= 10 => Results.Typed.Ok(new Todo(id, "Walk the dog")), _ => Results.Typed.NotFound() - }; -}); + }); var extensions = new Dictionary() { { "traceId", "traceId123" } }; From e1f6ccd2b159a73b928792511285a9d0dca83263 Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Fri, 8 Apr 2022 17:36:10 -0700 Subject: [PATCH 09/35] Api updates --- src/Http/Http.Results/src/Content.cs | 18 +- src/Http/Http.Results/src/Created.cs | 1 - .../Http.Results/src/HttpResultsHelper.cs | 37 +- src/Http/Http.Results/src/Json.cs | 6 +- src/Http/Http.Results/src/Ok.cs | 1 - .../Http.Results/src/PublicAPI.Unshipped.txt | 370 +++++++++++------- src/Http/Http.Results/src/Results.cs | 6 +- src/Http/Http.Results/src/TypedResults.cs | 19 +- 8 files changed, 270 insertions(+), 188 deletions(-) diff --git a/src/Http/Http.Results/src/Content.cs b/src/Http/Http.Results/src/Content.cs index 22f00c758e06..bbf09845ca25 100644 --- a/src/Http/Http.Results/src/Content.cs +++ b/src/Http/Http.Results/src/Content.cs @@ -7,13 +7,13 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.Logging; /// -/// An that when executed +/// An that when executed /// will produce a response with content. /// public sealed partial class Content : IResult { /// - /// Initializes a new instance of the class with the values. + /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. /// The Content-Type header for the response @@ -23,7 +23,7 @@ internal Content(string? content, string? contentType) } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// /// The value to format in the entity body. /// The HTTP status code of the response. @@ -61,6 +61,16 @@ public Task ExecuteAsync(HttpContext httpContext) var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.ContentResult"); - return HttpResultsHelper.WriteResultAsContentAsync(httpContext, logger, ResponseContent, StatusCode, ContentType); + if (StatusCode is { } statusCode) + { + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, statusCode); + httpContext.Response.StatusCode = statusCode; + } + + return HttpResultsHelper.WriteResultAsContentAsync( + httpContext, + logger, + ResponseContent, + ContentType); } } diff --git a/src/Http/Http.Results/src/Created.cs b/src/Http/Http.Results/src/Created.cs index a0e34db546eb..fbc72e287af4 100644 --- a/src/Http/Http.Results/src/Created.cs +++ b/src/Http/Http.Results/src/Created.cs @@ -27,7 +27,6 @@ internal Created(string location) /// provided. /// /// The location at which the content has been created. - /// The value to format in the entity body. internal Created(Uri locationUri) { if (locationUri == null) diff --git a/src/Http/Http.Results/src/HttpResultsHelper.cs b/src/Http/Http.Results/src/HttpResultsHelper.cs index 361f1f093fd0..b93cd489d5a5 100644 --- a/src/Http/Http.Results/src/HttpResultsHelper.cs +++ b/src/Http/Http.Results/src/HttpResultsHelper.cs @@ -23,18 +23,13 @@ public static Task WriteResultAsJsonAsync( string? contentType = null, JsonSerializerOptions? jsonSerializerOptions = null) { - //Log.WritingResultAsJson(logger, value, statusCode); - - //if (statusCode is { } code) - //{ - // httpContext.Response.StatusCode = code; - //} - if (value is null) { return Task.CompletedTask; } + Log.WritingResultAsJson(logger, value); + return httpContext.Response.WriteAsJsonAsync( value, value.GetType(), @@ -46,7 +41,6 @@ public static Task WriteResultAsContentAsync( HttpContext httpContext, ILogger logger, string? content, - int? statusCode, string? contentType = null) { var response = httpContext.Response; @@ -60,11 +54,6 @@ public static Task WriteResultAsContentAsync( response.ContentType = resolvedContentType; - if (statusCode is { } code) - { - response.StatusCode = code; - } - Log.WritingResultAsContent(logger, resolvedContentType); if (content != null) @@ -163,19 +152,12 @@ public static void ApplyProblemDetailsDefaults(ProblemDetails problemDetails, in internal static partial class Log { - public static void WritingResultAsJson(ILogger logger, object? value, int? statusCode) + public static void WritingResultAsJson(ILogger logger, object value) { if (logger.IsEnabled(LogLevel.Information)) { - if (value is null) - { - WritingResultAsJsonWithoutValue(logger, statusCode ?? StatusCodes.Status200OK); - } - else - { - var valueType = value.GetType().FullName!; - WritingResultAsJson(logger, type: valueType, statusCode ?? StatusCodes.Status200OK); - } + var valueType = value.GetType().FullName!; + WritingResultAsJson(logger, type: valueType); } } public static void WritingResultAsFile(ILogger logger, string fileDownloadName) @@ -196,15 +178,10 @@ public static void WritingResultAsFile(ILogger logger, string fileDownloadName) EventName = "WritingResultAsContent")] public static partial void WritingResultAsContent(ILogger logger, string contentType); - [LoggerMessage(3, LogLevel.Information, "Writing value of type '{Type}' as Json with status code '{StatusCode}'.", + [LoggerMessage(3, LogLevel.Information, "Writing value of type '{Type}' as Json.", EventName = "WritingResultAsJson", SkipEnabledCheck = true)] - private static partial void WritingResultAsJson(ILogger logger, string type, int statusCode); - - [LoggerMessage(4, LogLevel.Information, "Setting the status code '{StatusCode}' without value.", - EventName = "WritingResultAsJsonWithoutValue", - SkipEnabledCheck = true)] - private static partial void WritingResultAsJsonWithoutValue(ILogger logger, int statusCode); + private static partial void WritingResultAsJson(ILogger logger, string type); [LoggerMessage(5, LogLevel.Information, "Sending file with download name '{FileDownloadName}'.", diff --git a/src/Http/Http.Results/src/Json.cs b/src/Http/Http.Results/src/Json.cs index 014cc4d7e4e6..2474623f7ffe 100644 --- a/src/Http/Http.Results/src/Json.cs +++ b/src/Http/Http.Results/src/Json.cs @@ -95,10 +95,10 @@ public Task ExecuteAsync(HttpContext httpContext) var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Result.JsonResult"); - if (StatusCode is { } code) + if (StatusCode is { } statusCode) { - HttpResultsHelper.Log.WritingResultAsStatusCode(logger, code); - httpContext.Response.StatusCode = code; + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, statusCode); + httpContext.Response.StatusCode = statusCode; } return HttpResultsHelper.WriteResultAsJsonAsync( diff --git a/src/Http/Http.Results/src/Ok.cs b/src/Http/Http.Results/src/Ok.cs index 0c9e51bd240c..48e2780e23e3 100644 --- a/src/Http/Http.Results/src/Ok.cs +++ b/src/Http/Http.Results/src/Ok.cs @@ -16,7 +16,6 @@ public sealed class Ok : IResult /// /// Initializes a new instance of the class with the values. /// - /// The value to format in the entity body. internal Ok() { } diff --git a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt index 162a8ca3601f..3d6320905c3c 100644 --- a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt @@ -1,119 +1,181 @@ #nullable enable -Microsoft.AspNetCore.Http.AcceptedAtRouteHttpResult -Microsoft.AspNetCore.Http.AcceptedAtRouteHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.AcceptedAtRouteHttpResult.RouteName.get -> string? -Microsoft.AspNetCore.Http.AcceptedAtRouteHttpResult.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary! -Microsoft.AspNetCore.Http.AcceptedAtRouteHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.AcceptedAtRouteHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.AcceptedHttpResult -Microsoft.AspNetCore.Http.AcceptedHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.AcceptedHttpResult.Location.get -> string? -Microsoft.AspNetCore.Http.AcceptedHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.AcceptedHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.BadRequestObjectHttpResult -Microsoft.AspNetCore.Http.BadRequestObjectHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.BadRequestObjectHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.BadRequestObjectHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.ChallengeHttpResult -Microsoft.AspNetCore.Http.ChallengeHttpResult.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! -Microsoft.AspNetCore.Http.ChallengeHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.ChallengeHttpResult.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? -Microsoft.AspNetCore.Http.ConflictObjectHttpResult -Microsoft.AspNetCore.Http.ConflictObjectHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.ConflictObjectHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.ConflictObjectHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.ContentHttpResult -Microsoft.AspNetCore.Http.ContentHttpResult.Content.get -> string? -Microsoft.AspNetCore.Http.ContentHttpResult.ContentType.get -> string? -Microsoft.AspNetCore.Http.ContentHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.ContentHttpResult.StatusCode.get -> int? -Microsoft.AspNetCore.Http.CreatedAtRouteHttpResult -Microsoft.AspNetCore.Http.CreatedAtRouteHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.CreatedAtRouteHttpResult.RouteName.get -> string? -Microsoft.AspNetCore.Http.CreatedAtRouteHttpResult.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? -Microsoft.AspNetCore.Http.CreatedAtRouteHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.CreatedAtRouteHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.CreatedHttpResult -Microsoft.AspNetCore.Http.CreatedHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.CreatedHttpResult.Location.get -> string? -Microsoft.AspNetCore.Http.CreatedHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.CreatedHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.EmptyHttpResult -Microsoft.AspNetCore.Http.EmptyHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.FileContentHttpResult -Microsoft.AspNetCore.Http.FileContentHttpResult.ContentType.get -> string! -Microsoft.AspNetCore.Http.FileContentHttpResult.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.FileContentHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.FileContentHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.FileContentHttpResult.FileContents.get -> System.ReadOnlyMemory -Microsoft.AspNetCore.Http.FileContentHttpResult.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.FileContentHttpResult.FileLength.get -> long? -Microsoft.AspNetCore.Http.FileContentHttpResult.LastModified.get -> System.DateTimeOffset? -Microsoft.AspNetCore.Http.FileStreamHttpResult -Microsoft.AspNetCore.Http.FileStreamHttpResult.ContentType.get -> string! -Microsoft.AspNetCore.Http.FileStreamHttpResult.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.FileStreamHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.FileStreamHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.FileStreamHttpResult.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.FileStreamHttpResult.FileLength.get -> long? -Microsoft.AspNetCore.Http.FileStreamHttpResult.FileStream.get -> System.IO.Stream! -Microsoft.AspNetCore.Http.FileStreamHttpResult.LastModified.get -> System.DateTimeOffset? -Microsoft.AspNetCore.Http.ForbidHttpResult -Microsoft.AspNetCore.Http.ForbidHttpResult.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! -Microsoft.AspNetCore.Http.ForbidHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.ForbidHttpResult.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? -Microsoft.AspNetCore.Http.JsonHttpResult -Microsoft.AspNetCore.Http.JsonHttpResult.ContentType.get -> string? -Microsoft.AspNetCore.Http.JsonHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.JsonHttpResult.JsonSerializerOptions.get -> System.Text.Json.JsonSerializerOptions? -Microsoft.AspNetCore.Http.JsonHttpResult.StatusCode.get -> int? -Microsoft.AspNetCore.Http.JsonHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.NoContentHttpResult -Microsoft.AspNetCore.Http.NoContentHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.NoContentHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.NotFoundObjectHttpResult -Microsoft.AspNetCore.Http.NotFoundObjectHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.NotFoundObjectHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.NotFoundObjectHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.OkObjectHttpResult -Microsoft.AspNetCore.Http.OkObjectHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.OkObjectHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.OkObjectHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.PhysicalFileHttpResult -Microsoft.AspNetCore.Http.PhysicalFileHttpResult.ContentType.get -> string! -Microsoft.AspNetCore.Http.PhysicalFileHttpResult.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.PhysicalFileHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.PhysicalFileHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.PhysicalFileHttpResult.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.PhysicalFileHttpResult.FileLength.get -> long? -Microsoft.AspNetCore.Http.PhysicalFileHttpResult.FileName.get -> string! -Microsoft.AspNetCore.Http.PhysicalFileHttpResult.LastModified.get -> System.DateTimeOffset? -Microsoft.AspNetCore.Http.ProblemHttpResult -Microsoft.AspNetCore.Http.ProblemHttpResult.ContentType.get -> string! -Microsoft.AspNetCore.Http.ProblemHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.ProblemHttpResult.ProblemDetails.get -> Microsoft.AspNetCore.Mvc.ProblemDetails! -Microsoft.AspNetCore.Http.ProblemHttpResult.StatusCode.get -> int? -Microsoft.AspNetCore.Http.PushStreamHttpResult -Microsoft.AspNetCore.Http.PushStreamHttpResult.ContentType.get -> string! -Microsoft.AspNetCore.Http.PushStreamHttpResult.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.PushStreamHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.PushStreamHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.PushStreamHttpResult.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.PushStreamHttpResult.FileLength.get -> long? -Microsoft.AspNetCore.Http.PushStreamHttpResult.LastModified.get -> System.DateTimeOffset? -Microsoft.AspNetCore.Http.RedirectHttpResult -Microsoft.AspNetCore.Http.RedirectHttpResult.AcceptLocalUrlOnly.get -> bool -Microsoft.AspNetCore.Http.RedirectHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.RedirectHttpResult.Permanent.get -> bool -Microsoft.AspNetCore.Http.RedirectHttpResult.PreserveMethod.get -> bool -Microsoft.AspNetCore.Http.RedirectHttpResult.Url.get -> string! -Microsoft.AspNetCore.Http.RedirectToRouteHttpResult -Microsoft.AspNetCore.Http.RedirectToRouteHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.RedirectToRouteHttpResult.Fragment.get -> string? -Microsoft.AspNetCore.Http.RedirectToRouteHttpResult.Permanent.get -> bool -Microsoft.AspNetCore.Http.RedirectToRouteHttpResult.PreserveMethod.get -> bool -Microsoft.AspNetCore.Http.RedirectToRouteHttpResult.RouteName.get -> string? -Microsoft.AspNetCore.Http.RedirectToRouteHttpResult.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? +Microsoft.AspNetCore.Http.HttpResults.Accepted +Microsoft.AspNetCore.Http.HttpResults.Accepted.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Accepted.Location.get -> string? +Microsoft.AspNetCore.Http.HttpResults.Accepted.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.Accepted +Microsoft.AspNetCore.Http.HttpResults.Accepted.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Accepted.Location.get -> string? +Microsoft.AspNetCore.Http.HttpResults.Accepted.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.Accepted.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute.RouteName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary! +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute.RouteName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary! +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.BadRequest +Microsoft.AspNetCore.Http.HttpResults.BadRequest.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.BadRequest.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.BadRequest +Microsoft.AspNetCore.Http.HttpResults.BadRequest.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.BadRequest.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.BadRequest.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.Challenge +Microsoft.AspNetCore.Http.HttpResults.Challenge.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! +Microsoft.AspNetCore.Http.HttpResults.Challenge.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Challenge.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? +Microsoft.AspNetCore.Http.HttpResults.Conflict +Microsoft.AspNetCore.Http.HttpResults.Conflict.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Conflict.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.Conflict +Microsoft.AspNetCore.Http.HttpResults.Conflict.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Conflict.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.Conflict.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.Content +Microsoft.AspNetCore.Http.HttpResults.Content.ContentType.get -> string? +Microsoft.AspNetCore.Http.HttpResults.Content.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Content.ResponseContent.get -> string? +Microsoft.AspNetCore.Http.HttpResults.Content.StatusCode.get -> int? +Microsoft.AspNetCore.Http.HttpResults.Created +Microsoft.AspNetCore.Http.HttpResults.Created.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Created.Location.get -> string? +Microsoft.AspNetCore.Http.HttpResults.Created.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.Created +Microsoft.AspNetCore.Http.HttpResults.Created.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Created.Location.get -> string? +Microsoft.AspNetCore.Http.HttpResults.Created.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.Created.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.Empty +Microsoft.AspNetCore.Http.HttpResults.Empty.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.FileContent +Microsoft.AspNetCore.Http.HttpResults.FileContent.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.FileContent.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.FileContent.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.FileContent.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.FileContent.FileContents.get -> System.ReadOnlyMemory +Microsoft.AspNetCore.Http.HttpResults.FileContent.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.FileContent.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.FileContent.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.HttpResults.Forbid +Microsoft.AspNetCore.Http.HttpResults.Forbid.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! +Microsoft.AspNetCore.Http.HttpResults.Forbid.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Forbid.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? +Microsoft.AspNetCore.Http.HttpResults.HttpFileStream +Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.FileStream.get -> System.IO.Stream! +Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.HttpResults.Json +Microsoft.AspNetCore.Http.HttpResults.Json.ContentType.get -> string? +Microsoft.AspNetCore.Http.HttpResults.Json.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Json.JsonSerializerOptions.get -> System.Text.Json.JsonSerializerOptions? +Microsoft.AspNetCore.Http.HttpResults.Json.StatusCode.get -> int? +Microsoft.AspNetCore.Http.HttpResults.Json.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.NoContent +Microsoft.AspNetCore.Http.HttpResults.NoContent.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.NoContent.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.NotFound +Microsoft.AspNetCore.Http.HttpResults.NotFound.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.NotFound.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.NotFound +Microsoft.AspNetCore.Http.HttpResults.NotFound.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.NotFound.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.NotFound.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.Ok +Microsoft.AspNetCore.Http.HttpResults.Ok.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Ok.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.Ok +Microsoft.AspNetCore.Http.HttpResults.Ok.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Ok.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.Ok.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.PhysicalFile +Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.FileName.get -> string! +Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.HttpResults.Problem +Microsoft.AspNetCore.Http.HttpResults.Problem.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.Problem.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Problem.ProblemDetails.get -> Microsoft.AspNetCore.Mvc.ProblemDetails! +Microsoft.AspNetCore.Http.HttpResults.Problem.StatusCode.get -> int? +Microsoft.AspNetCore.Http.HttpResults.PushStream +Microsoft.AspNetCore.Http.HttpResults.PushStream.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.PushStream.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.PushStream.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.PushStream.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.PushStream.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.PushStream.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.PushStream.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.HttpResults.Redirect +Microsoft.AspNetCore.Http.HttpResults.Redirect.AcceptLocalUrlOnly.get -> bool +Microsoft.AspNetCore.Http.HttpResults.Redirect.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Redirect.Permanent.get -> bool +Microsoft.AspNetCore.Http.HttpResults.Redirect.PreserveMethod.get -> bool +Microsoft.AspNetCore.Http.HttpResults.Redirect.Url.get -> string! +Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute +Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.Fragment.get -> string? +Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.Permanent.get -> bool +Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.PreserveMethod.get -> bool +Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.RouteName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? +Microsoft.AspNetCore.Http.HttpResults.SignIn +Microsoft.AspNetCore.Http.HttpResults.SignIn.AuthenticationScheme.get -> string? +Microsoft.AspNetCore.Http.HttpResults.SignIn.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.SignIn.Principal.get -> System.Security.Claims.ClaimsPrincipal! +Microsoft.AspNetCore.Http.HttpResults.SignIn.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? +Microsoft.AspNetCore.Http.HttpResults.SignOut +Microsoft.AspNetCore.Http.HttpResults.SignOut.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! +Microsoft.AspNetCore.Http.HttpResults.SignOut.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.SignOut.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? +Microsoft.AspNetCore.Http.HttpResults.Status +Microsoft.AspNetCore.Http.HttpResults.Status.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Status.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.Unauthorized +Microsoft.AspNetCore.Http.HttpResults.Unauthorized.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Unauthorized.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity +Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity +Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.VirtualFile +Microsoft.AspNetCore.Http.HttpResults.VirtualFile.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.VirtualFile.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.VirtualFile.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.VirtualFile.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.VirtualFile.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.VirtualFile.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.VirtualFile.FileName.get -> string! +Microsoft.AspNetCore.Http.HttpResults.VirtualFile.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.Results.Typed Microsoft.AspNetCore.Http.Results Microsoft.AspNetCore.Http.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! @@ -129,6 +191,55 @@ Microsoft.AspNetCore.Http.Results.Result.get -> Mi Microsoft.AspNetCore.Http.Results Microsoft.AspNetCore.Http.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! +static Microsoft.AspNetCore.Http.HttpResults.Empty.Instance.get -> Microsoft.AspNetCore.Http.HttpResults.Empty! +static Microsoft.AspNetCore.Http.Results.Typed.Accepted(System.Uri! uri) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! +static Microsoft.AspNetCore.Http.Results.Typed.Accepted(string! uri) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! +static Microsoft.AspNetCore.Http.Results.Typed.Accepted(System.Uri! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! +static Microsoft.AspNetCore.Http.Results.Typed.Accepted(string! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! +static Microsoft.AspNetCore.Http.Results.Typed.AcceptedAtRoute(string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute! +static Microsoft.AspNetCore.Http.Results.Typed.AcceptedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute! +static Microsoft.AspNetCore.Http.Results.Typed.BadRequest() -> Microsoft.AspNetCore.Http.HttpResults.BadRequest! +static Microsoft.AspNetCore.Http.Results.Typed.BadRequest(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.BadRequest! +static Microsoft.AspNetCore.Http.Results.Typed.Bytes(System.ReadOnlyMemory contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.FileContent! +static Microsoft.AspNetCore.Http.Results.Typed.Bytes(byte[]! contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.FileContent! +static Microsoft.AspNetCore.Http.Results.Typed.Challenge(Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, System.Collections.Generic.IList? authenticationSchemes = null) -> Microsoft.AspNetCore.Http.HttpResults.Challenge! +static Microsoft.AspNetCore.Http.Results.Typed.Conflict() -> Microsoft.AspNetCore.Http.HttpResults.Conflict! +static Microsoft.AspNetCore.Http.Results.Typed.Conflict(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.Conflict! +static Microsoft.AspNetCore.Http.Results.Typed.Content(string! content, Microsoft.Net.Http.Headers.MediaTypeHeaderValue! contentType) -> Microsoft.AspNetCore.Http.HttpResults.Content! +static Microsoft.AspNetCore.Http.Results.Typed.Content(string! content, string? contentType = null, System.Text.Encoding? contentEncoding = null) -> Microsoft.AspNetCore.Http.HttpResults.Content! +static Microsoft.AspNetCore.Http.Results.Typed.Created(System.Uri! uri) -> Microsoft.AspNetCore.Http.HttpResults.Created! +static Microsoft.AspNetCore.Http.Results.Typed.Created(string! uri) -> Microsoft.AspNetCore.Http.HttpResults.Created! +static Microsoft.AspNetCore.Http.Results.Typed.Created(System.Uri! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Created! +static Microsoft.AspNetCore.Http.Results.Typed.Created(string! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Created! +static Microsoft.AspNetCore.Http.Results.Typed.CreatedAtRoute(string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute! +static Microsoft.AspNetCore.Http.Results.Typed.CreatedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute! +static Microsoft.AspNetCore.Http.Results.Typed.File(System.IO.Stream! fileStream, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.HttpFileStream! +static Microsoft.AspNetCore.Http.Results.Typed.File(byte[]! fileContents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.FileContent! +static Microsoft.AspNetCore.Http.Results.Typed.Forbid(Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, System.Collections.Generic.IList? authenticationSchemes = null) -> Microsoft.AspNetCore.Http.HttpResults.Forbid! +static Microsoft.AspNetCore.Http.Results.Typed.Json(TValue? data, System.Text.Json.JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) -> Microsoft.AspNetCore.Http.HttpResults.Json! +static Microsoft.AspNetCore.Http.Results.Typed.LocalRedirect(string! localUrl, bool permanent = false, bool preserveMethod = false) -> Microsoft.AspNetCore.Http.HttpResults.Redirect! +static Microsoft.AspNetCore.Http.Results.Typed.NoContent() -> Microsoft.AspNetCore.Http.HttpResults.NoContent! +static Microsoft.AspNetCore.Http.Results.Typed.NotFound() -> Microsoft.AspNetCore.Http.HttpResults.NotFound! +static Microsoft.AspNetCore.Http.Results.Typed.NotFound(TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.NotFound! +static Microsoft.AspNetCore.Http.Results.Typed.Ok() -> Microsoft.AspNetCore.Http.HttpResults.Ok! +static Microsoft.AspNetCore.Http.Results.Typed.Ok(TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Ok! +static Microsoft.AspNetCore.Http.Results.Typed.PhysicalFile(string! path, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.PhysicalFile! +static Microsoft.AspNetCore.Http.Results.Typed.Problem(Microsoft.AspNetCore.Mvc.ProblemDetails! problemDetails) -> Microsoft.AspNetCore.Http.HttpResults.Problem! +static Microsoft.AspNetCore.Http.Results.Typed.Problem(string? detail = null, string? instance = null, int? statusCode = null, string? title = null, string? type = null, System.Collections.Generic.IDictionary? extensions = null) -> Microsoft.AspNetCore.Http.HttpResults.Problem! +static Microsoft.AspNetCore.Http.Results.Typed.Redirect(string! url, bool permanent = false, bool preserveMethod = false) -> Microsoft.AspNetCore.Http.HttpResults.Redirect! +static Microsoft.AspNetCore.Http.Results.Typed.RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) -> Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute! +static Microsoft.AspNetCore.Http.Results.Typed.SignIn(System.Security.Claims.ClaimsPrincipal! principal, Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, string? authenticationScheme = null) -> Microsoft.AspNetCore.Http.HttpResults.SignIn! +static Microsoft.AspNetCore.Http.Results.Typed.SignOut(Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, System.Collections.Generic.IList? authenticationSchemes = null) -> Microsoft.AspNetCore.Http.HttpResults.SignOut! +static Microsoft.AspNetCore.Http.Results.Typed.StatusCode(int statusCode) -> Microsoft.AspNetCore.Http.HttpResults.Status! +static Microsoft.AspNetCore.Http.Results.Typed.Stream(System.Func! streamWriterCallback, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.PushStream! +static Microsoft.AspNetCore.Http.Results.Typed.Stream(System.IO.Pipelines.PipeReader! pipeReader, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.HttpFileStream! +static Microsoft.AspNetCore.Http.Results.Typed.Stream(System.IO.Stream! stream, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.HttpFileStream! +static Microsoft.AspNetCore.Http.Results.Typed.Text(string! content, string? contentType = null, System.Text.Encoding? contentEncoding = null) -> Microsoft.AspNetCore.Http.HttpResults.Content! +static Microsoft.AspNetCore.Http.Results.Typed.Unauthorized() -> Microsoft.AspNetCore.Http.HttpResults.Unauthorized! +static Microsoft.AspNetCore.Http.Results.Typed.UnprocessableEntity() -> Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity! +static Microsoft.AspNetCore.Http.Results.Typed.UnprocessableEntity(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity! +static Microsoft.AspNetCore.Http.Results.Typed.ValidationProblem(System.Collections.Generic.IDictionary! errors, string? detail = null, string? instance = null, int? statusCode = null, string? title = null, string? type = null, System.Collections.Generic.IDictionary? extensions = null) -> Microsoft.AspNetCore.Http.HttpResults.Problem! +static Microsoft.AspNetCore.Http.Results.Typed.VirtualFile(string! path, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.VirtualFile! static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.Results! static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.Results! static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.Results! @@ -149,35 +260,6 @@ static Microsoft.AspNetCore.Http.Results.implicit static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.Results! static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.Results! static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.Results! -Microsoft.AspNetCore.Http.SignInHttpResult -Microsoft.AspNetCore.Http.SignInHttpResult.AuthenticationScheme.get -> string? -Microsoft.AspNetCore.Http.SignInHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.SignInHttpResult.Principal.get -> System.Security.Claims.ClaimsPrincipal! -Microsoft.AspNetCore.Http.SignInHttpResult.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? -Microsoft.AspNetCore.Http.SignOutHttpResult -Microsoft.AspNetCore.Http.SignOutHttpResult.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! -Microsoft.AspNetCore.Http.SignOutHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.SignOutHttpResult.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? -Microsoft.AspNetCore.Http.StatusCodeHttpResult -Microsoft.AspNetCore.Http.StatusCodeHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.StatusCodeHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.UnauthorizedHttpResult -Microsoft.AspNetCore.Http.UnauthorizedHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.UnauthorizedHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.UnprocessableEntityObjectHttpResult -Microsoft.AspNetCore.Http.UnprocessableEntityObjectHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.UnprocessableEntityObjectHttpResult.StatusCode.get -> int -Microsoft.AspNetCore.Http.UnprocessableEntityObjectHttpResult.Value.get -> object? -Microsoft.AspNetCore.Http.VirtualFileHttpResult -Microsoft.AspNetCore.Http.VirtualFileHttpResult.ContentType.get -> string! -Microsoft.AspNetCore.Http.VirtualFileHttpResult.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.VirtualFileHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.VirtualFileHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.VirtualFileHttpResult.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.VirtualFileHttpResult.FileLength.get -> long? -Microsoft.AspNetCore.Http.VirtualFileHttpResult.FileName.get -> string! -Microsoft.AspNetCore.Http.VirtualFileHttpResult.LastModified.get -> System.DateTimeOffset? -static Microsoft.AspNetCore.Http.EmptyHttpResult.Instance.get -> Microsoft.AspNetCore.Http.EmptyHttpResult! static Microsoft.AspNetCore.Http.Results.Bytes(System.ReadOnlyMemory contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.IResult! static Microsoft.AspNetCore.Http.Results.Empty.get -> Microsoft.AspNetCore.Http.IResult! static Microsoft.AspNetCore.Http.Results.Stream(System.Func! streamWriterCallback, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.IResult! diff --git a/src/Http/Http.Results/src/Results.cs b/src/Http/Http.Results/src/Results.cs index e6f0a5e69cc9..3b23c408ac8d 100644 --- a/src/Http/Http.Results/src/Results.cs +++ b/src/Http/Http.Results/src/Results.cs @@ -134,7 +134,7 @@ public static IResult Content(string content, MediaTypeHeaderValue contentType) /// The serializer options to use when serializing the value. /// The content-type to set on the response. /// The status code to set on the response. - /// The created that serializes the specified + /// The created that serializes the specified /// as JSON format for the response. /// Callers should cache an instance of serializer settings to avoid /// recreating cached data with each call. @@ -491,10 +491,10 @@ public static IResult RedirectToRoute(string? routeName = null, object? routeVal fragment: fragment); /// - /// Creates a object by specifying a . + /// Creates a object by specifying a . /// /// The status code to set on the response. - /// The created object for the response. + /// The created object for the response. public static IResult StatusCode(int statusCode) => ResultsCache.StatusCode(statusCode); diff --git a/src/Http/Http.Results/src/TypedResults.cs b/src/Http/Http.Results/src/TypedResults.cs index ee5b4b300904..ded0af9549d4 100644 --- a/src/Http/Http.Results/src/TypedResults.cs +++ b/src/Http/Http.Results/src/TypedResults.cs @@ -18,6 +18,9 @@ namespace Microsoft.AspNetCore.Http; /// public static partial class Results { + /// + /// A typed factory for . + /// public static class Typed { /// @@ -195,7 +198,9 @@ public static FileContent File( /// The of when the file was last modified. /// The associated with the file. /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static FileContent Bytes( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters byte[] contents, string? contentType = null, string? fileDownloadName = null, @@ -304,7 +309,9 @@ public static HttpFileStream File( /// /// The parameter is disposed after the response is sent. /// +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static HttpFileStream Stream( +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters Stream stream, string? contentType = null, string? fileDownloadName = null, @@ -513,10 +520,10 @@ public static RedirectToRoute RedirectToRoute(string? routeName = null, object? fragment: fragment); /// - /// Creates a object by specifying a . + /// Creates a object by specifying a . /// /// The status code to set on the response. - /// The created object for the response. + /// The created object for the response. public static Status StatusCode(int statusCode) => ResultsCache.StatusCode(statusCode); @@ -755,7 +762,9 @@ public static Created Created(Uri uri, TValue? value) /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static CreatedAtRoute CreatedAtRoute(string? routeName = null, object? routeValues = null) +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters => new(routeName, routeValues); /// @@ -765,7 +774,9 @@ public static CreatedAtRoute CreatedAtRoute(string? routeName = null, object? ro /// The route data to use for generating the URL. /// The value to be included in the HTTP response body. /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static CreatedAtRoute CreatedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters => new(routeName, routeValues, value); /// @@ -836,7 +847,9 @@ public static Accepted Accepted(Uri uri, TValue? value) /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static AcceptedAtRoute AcceptedAtRoute(string? routeName = null, object? routeValues = null) +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters => new(routeName, routeValues); /// @@ -846,7 +859,9 @@ public static AcceptedAtRoute AcceptedAtRoute(string? routeName = null, object? /// The route data to use for generating the URL. /// The value to be included in the HTTP response body. /// The created for the response. +#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static AcceptedAtRoute AcceptedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) +#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters => new(routeName, routeValues, value); } } From 877d0937f0ac43d96f9c86f627824a1ffd180f95 Mon Sep 17 00:00:00 2001 From: Bruno Lins de Oliveira Date: Sat, 9 Apr 2022 20:54:33 -0700 Subject: [PATCH 10/35] Updating helper --- .../Http.Results/src/HttpResultsHelper.cs | 28 ++++--------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/Http/Http.Results/src/HttpResultsHelper.cs b/src/Http/Http.Results/src/HttpResultsHelper.cs index b93cd489d5a5..f510def3d8b7 100644 --- a/src/Http/Http.Results/src/HttpResultsHelper.cs +++ b/src/Http/Http.Results/src/HttpResultsHelper.cs @@ -28,7 +28,7 @@ public static Task WriteResultAsJsonAsync( return Task.CompletedTask; } - Log.WritingResultAsJson(logger, value); + Log.WritingResultAsJson(logger, typeof(T).Name); return httpContext.Response.WriteAsJsonAsync( value, @@ -152,22 +152,6 @@ public static void ApplyProblemDetailsDefaults(ProblemDetails problemDetails, in internal static partial class Log { - public static void WritingResultAsJson(ILogger logger, object value) - { - if (logger.IsEnabled(LogLevel.Information)) - { - var valueType = value.GetType().FullName!; - WritingResultAsJson(logger, type: valueType); - } - } - public static void WritingResultAsFile(ILogger logger, string fileDownloadName) - { - if (logger.IsEnabled(LogLevel.Information)) - { - WritingResultAsFileWithNoFileName(logger, fileDownloadName: fileDownloadName); - } - } - [LoggerMessage(1, LogLevel.Information, "Setting HTTP status code {StatusCode}.", EventName = "WritingResultAsStatusCode")] @@ -179,14 +163,12 @@ public static void WritingResultAsFile(ILogger logger, string fileDownloadName) public static partial void WritingResultAsContent(ILogger logger, string contentType); [LoggerMessage(3, LogLevel.Information, "Writing value of type '{Type}' as Json.", - EventName = "WritingResultAsJson", - SkipEnabledCheck = true)] - private static partial void WritingResultAsJson(ILogger logger, string type); + EventName = "WritingResultAsJson")] + public static partial void WritingResultAsJson(ILogger logger, string type); [LoggerMessage(5, LogLevel.Information, "Sending file with download name '{FileDownloadName}'.", - EventName = "WritingResultAsFileWithNoFileName", - SkipEnabledCheck = true)] - private static partial void WritingResultAsFileWithNoFileName(ILogger logger, string fileDownloadName); + EventName = "WritingResultAsFileWithNoFileName")] + public static partial void WritingResultAsFile(ILogger logger, string fileDownloadName); } } From 1825177bb02d962e648e61f72add9ad0c3529799 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Mon, 11 Apr 2022 15:33:44 -0700 Subject: [PATCH 11/35] Post-rebase fixes --- src/Http/Http.Results/src/Results.cs | 10 +++++----- .../Http.Results/test/ResultsOfTTests.Generated.cs | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Http/Http.Results/src/Results.cs b/src/Http/Http.Results/src/Results.cs index 3b23c408ac8d..b062ae3c1c04 100644 --- a/src/Http/Http.Results/src/Results.cs +++ b/src/Http/Http.Results/src/Results.cs @@ -504,7 +504,7 @@ public static IResult StatusCode(int statusCode) /// The value to be included in the HTTP response body. /// The created for the response. public static IResult NotFound(object? value = null) - => value is null ? ResultsCache.NotFound : new NotFoundObjectHttpResult(value); + => value is null ? ResultsCache.NotFound : new NotFound(value); /// /// Produces a response. @@ -519,7 +519,7 @@ public static IResult Unauthorized() /// An error object to be included in the HTTP response body. /// The created for the response. public static IResult BadRequest(object? error = null) - => error is null ? ResultsCache.BadRequest : new BadRequestObjectHttpResult(error); + => error is null ? ResultsCache.BadRequest : new BadRequest(error); /// /// Produces a response. @@ -527,7 +527,7 @@ public static IResult BadRequest(object? error = null) /// An error object to be included in the HTTP response body. /// The created for the response. public static IResult Conflict(object? error = null) - => error is null ? ResultsCache.Conflict : new ConflictObjectHttpResult(error); + => error is null ? ResultsCache.Conflict : new Conflict(error); /// /// Produces a response. @@ -542,7 +542,7 @@ public static IResult NoContent() /// The value to be included in the HTTP response body. /// The created for the response. public static IResult Ok(object? value = null) - => value is null ? ResultsCache.Ok : new OkObjectHttpResult(value); + => value is null ? ResultsCache.Ok : new Ok(value); /// /// Produces a response. @@ -550,7 +550,7 @@ public static IResult Ok(object? value = null) /// An error object to be included in the HTTP response body. /// The created for the response. public static IResult UnprocessableEntity(object? error = null) - => error is null ? ResultsCache.UnprocessableEntity : new UnprocessableEntityObjectHttpResult(error); + => error is null ? ResultsCache.UnprocessableEntity : new UnprocessableEntity(error); /// /// Produces a response. diff --git a/src/Http/Http.Results/test/ResultsOfTTests.Generated.cs b/src/Http/Http.Results/test/ResultsOfTTests.Generated.cs index e776f41e5e6e..a17541fa7c2b 100644 --- a/src/Http/Http.Results/test/ResultsOfTTests.Generated.cs +++ b/src/Http/Http.Results/test/ResultsOfTTests.Generated.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Metadata; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; From 51a5623370a38a72a8e2f3f64111ee9a913b922d Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Mon, 11 Apr 2022 17:45:03 -0700 Subject: [PATCH 12/35] Implement IEndpointMetadataProvider on result types --- src/Http/Http.Results/src/Accepted.cs | 9 ++++++++- src/Http/Http.Results/src/AcceptedAtRoute.cs | 9 ++++++++- .../Http.Results/src/AcceptedAtRouteOfT.cs | 9 ++++++++- src/Http/Http.Results/src/AcceptedOfT.cs | 9 ++++++++- src/Http/Http.Results/src/BadRequest.cs | 9 ++++++++- src/Http/Http.Results/src/BadRequestOfT.cs | 9 ++++++++- src/Http/Http.Results/src/Conflict.cs | 9 ++++++++- src/Http/Http.Results/src/ConflictOfT.cs | 9 ++++++++- src/Http/Http.Results/src/Created.cs | 9 ++++++++- src/Http/Http.Results/src/CreatedAtRoute.cs | 9 ++++++++- src/Http/Http.Results/src/CreatedAtRouteOfT.cs | 9 ++++++++- src/Http/Http.Results/src/CreatedOfT.cs | 9 ++++++++- .../Microsoft.AspNetCore.Http.Results.csproj | 2 ++ src/Http/Http.Results/src/NoContent.cs | 9 ++++++++- src/Http/Http.Results/src/NotFound.cs | 9 ++++++++- src/Http/Http.Results/src/NotFoundOfT.cs | 9 ++++++++- src/Http/Http.Results/src/Ok.cs | 9 ++++++++- src/Http/Http.Results/src/OkOfT.cs | 9 ++++++++- src/Http/Http.Results/src/Problem.cs | 18 +++++++++++++++++- src/Http/Http.Results/src/Unauthorized.cs | 8 +++++++- .../Http.Results/src/UnprocessableEntity.cs | 9 ++++++++- .../Http.Results/src/UnprocessableEntityOfT.cs | 9 ++++++++- 22 files changed, 178 insertions(+), 21 deletions(-) diff --git a/src/Http/Http.Results/src/Accepted.cs b/src/Http/Http.Results/src/Accepted.cs index b2570c461009..fffc539461d2 100644 --- a/src/Http/Http.Results/src/Accepted.cs +++ b/src/Http/Http.Results/src/Accepted.cs @@ -4,6 +4,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// with status code Accepted (202) and Location header. /// Targets a registered route. /// -public sealed class Accepted : IResult +public sealed class Accepted : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -73,4 +74,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status202Accepted)); + } } diff --git a/src/Http/Http.Results/src/AcceptedAtRoute.cs b/src/Http/Http.Results/src/AcceptedAtRoute.cs index 012a2089fd8c..e2aa3d5799ce 100644 --- a/src/Http/Http.Results/src/AcceptedAtRoute.cs +++ b/src/Http/Http.Results/src/AcceptedAtRoute.cs @@ -4,6 +4,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -13,7 +14,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// with status code Accepted (202) and Location header. /// Targets a registered route. /// -public sealed class AcceptedAtRoute : IResult +public sealed class AcceptedAtRoute : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -80,4 +81,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status202Accepted)); + } } diff --git a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs index ea95d8b3c62b..0df45dea313a 100644 --- a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs @@ -4,6 +4,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -13,7 +14,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// with status code Accepted (202) and Location header. /// Targets a registered route. /// -public sealed class AcceptedAtRoute : IResult +public sealed class AcceptedAtRoute : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -90,4 +91,10 @@ public Task ExecuteAsync(HttpContext httpContext) return HttpResultsHelper.WriteResultAsJsonAsync(httpContext, logger, Value); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(TValue), StatusCodes.Status202Accepted, "application/json")); + } } diff --git a/src/Http/Http.Results/src/AcceptedOfT.cs b/src/Http/Http.Results/src/AcceptedOfT.cs index 68377469a345..0f971389a3f1 100644 --- a/src/Http/Http.Results/src/AcceptedOfT.cs +++ b/src/Http/Http.Results/src/AcceptedOfT.cs @@ -4,6 +4,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// with status code Accepted (202) and Location header. /// Targets a registered route. /// -public sealed class Accepted : IResult +public sealed class Accepted : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -88,4 +89,10 @@ public Task ExecuteAsync(HttpContext httpContext) logger, Value); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(TValue), StatusCodes.Status202Accepted, "application/json")); + } } diff --git a/src/Http/Http.Results/src/BadRequest.cs b/src/Http/Http.Results/src/BadRequest.cs index 4fc267e85ef3..536b3384d907 100644 --- a/src/Http/Http.Results/src/BadRequest.cs +++ b/src/Http/Http.Results/src/BadRequest.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Bad Request (400) status code. /// -public sealed class BadRequest : IResult +public sealed class BadRequest : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -37,4 +38,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status400BadRequest)); + } } diff --git a/src/Http/Http.Results/src/BadRequestOfT.cs b/src/Http/Http.Results/src/BadRequestOfT.cs index ae23feb605f8..be1a9358acd2 100644 --- a/src/Http/Http.Results/src/BadRequestOfT.cs +++ b/src/Http/Http.Results/src/BadRequestOfT.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Bad Request (400) status code. /// -public sealed class BadRequest : IResult +public sealed class BadRequest : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -48,4 +49,10 @@ public Task ExecuteAsync(HttpContext httpContext) logger: logger, Value); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(TValue), StatusCodes.Status400BadRequest, "application/json")); + } } diff --git a/src/Http/Http.Results/src/Conflict.cs b/src/Http/Http.Results/src/Conflict.cs index 00ce8edf25a1..39183233c44f 100644 --- a/src/Http/Http.Results/src/Conflict.cs +++ b/src/Http/Http.Results/src/Conflict.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Conflict (409) status code. /// -public sealed class Conflict : IResult +public sealed class Conflict : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -37,4 +38,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status409Conflict)); + } } diff --git a/src/Http/Http.Results/src/ConflictOfT.cs b/src/Http/Http.Results/src/ConflictOfT.cs index bb65cde4b346..bf5f5805ed83 100644 --- a/src/Http/Http.Results/src/ConflictOfT.cs +++ b/src/Http/Http.Results/src/ConflictOfT.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Conflict (409) status code. /// -public sealed class Conflict : IResult +public sealed class Conflict : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -48,4 +49,10 @@ public Task ExecuteAsync(HttpContext httpContext) logger: logger, Value); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(TValue), StatusCodes.Status409Conflict, "application/json")); + } } diff --git a/src/Http/Http.Results/src/Created.cs b/src/Http/Http.Results/src/Created.cs index fbc72e287af4..b082d27bf529 100644 --- a/src/Http/Http.Results/src/Created.cs +++ b/src/Http/Http.Results/src/Created.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with status code Created (201) and Location header. /// -public sealed class Created : IResult +public sealed class Created : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -69,4 +70,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status201Created)); + } } diff --git a/src/Http/Http.Results/src/CreatedAtRoute.cs b/src/Http/Http.Results/src/CreatedAtRoute.cs index 5cbe3e52988a..4a64e2afa203 100644 --- a/src/Http/Http.Results/src/CreatedAtRoute.cs +++ b/src/Http/Http.Results/src/CreatedAtRoute.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// with status code Created (201) and Location header. /// Targets a registered route. /// -public sealed class CreatedAtRoute : IResult +public sealed class CreatedAtRoute : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -79,4 +80,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status201Created)); + } } diff --git a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs index b39a170b439b..ddf14c0295d1 100644 --- a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// with status code Created (201) and Location header. /// Targets a registered route. /// -public sealed class CreatedAtRoute : IResult +public sealed class CreatedAtRoute : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -92,4 +93,10 @@ public Task ExecuteAsync(HttpContext httpContext) logger, Value); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(TValue), StatusCodes.Status201Created, "application/json")); + } } diff --git a/src/Http/Http.Results/src/CreatedOfT.cs b/src/Http/Http.Results/src/CreatedOfT.cs index b066bdc6d376..21f21ea56809 100644 --- a/src/Http/Http.Results/src/CreatedOfT.cs +++ b/src/Http/Http.Results/src/CreatedOfT.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with status code Created (201) and Location header. /// -public sealed class Created : IResult +public sealed class Created : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -84,4 +85,10 @@ public Task ExecuteAsync(HttpContext httpContext) logger, Value); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(TValue), StatusCodes.Status201Created, "application/json")); + } } diff --git a/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj b/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj index dc819c4ca160..de0934e22002 100644 --- a/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj +++ b/src/Http/Http.Results/src/Microsoft.AspNetCore.Http.Results.csproj @@ -17,6 +17,8 @@ + + diff --git a/src/Http/Http.Results/src/NoContent.cs b/src/Http/Http.Results/src/NoContent.cs index 7c63adcbf6da..15a41e82f21b 100644 --- a/src/Http/Http.Results/src/NoContent.cs +++ b/src/Http/Http.Results/src/NoContent.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// Represents an that when executed will /// produce an HTTP response with the No Content (204) status code. /// -public class NoContent : IResult +public class NoContent : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class. @@ -37,4 +38,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status204NoContent)); + } } diff --git a/src/Http/Http.Results/src/NotFound.cs b/src/Http/Http.Results/src/NotFound.cs index bc20b318e9ab..7a73995e95f4 100644 --- a/src/Http/Http.Results/src/NotFound.cs +++ b/src/Http/Http.Results/src/NotFound.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Not Found (404) status code. /// -public sealed class NotFound : IResult +public sealed class NotFound : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values. @@ -36,4 +37,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status404NotFound)); + } } diff --git a/src/Http/Http.Results/src/NotFoundOfT.cs b/src/Http/Http.Results/src/NotFoundOfT.cs index d61fab157a68..64a50640eaed 100644 --- a/src/Http/Http.Results/src/NotFoundOfT.cs +++ b/src/Http/Http.Results/src/NotFoundOfT.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Not Found (404) status code. /// -public sealed class NotFound : IResult +public sealed class NotFound : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values. @@ -47,4 +48,10 @@ public Task ExecuteAsync(HttpContext httpContext) logger: logger, Value); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(TValue), StatusCodes.Status404NotFound, "application/json")); + } } diff --git a/src/Http/Http.Results/src/Ok.cs b/src/Http/Http.Results/src/Ok.cs index 48e2780e23e3..9d59cac5f5c8 100644 --- a/src/Http/Http.Results/src/Ok.cs +++ b/src/Http/Http.Results/src/Ok.cs @@ -4,6 +4,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -11,7 +12,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Ok (200) status code. /// -public sealed class Ok : IResult +public sealed class Ok : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values. @@ -37,4 +38,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status200OK)); + } } diff --git a/src/Http/Http.Results/src/OkOfT.cs b/src/Http/Http.Results/src/OkOfT.cs index 2f25487a9b24..7506a79d08d0 100644 --- a/src/Http/Http.Results/src/OkOfT.cs +++ b/src/Http/Http.Results/src/OkOfT.cs @@ -4,6 +4,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -11,7 +12,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Ok (200) status code. /// -public sealed class Ok : IResult +public sealed class Ok : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values. @@ -48,4 +49,10 @@ public Task ExecuteAsync(HttpContext httpContext) logger: logger, Value); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(TValue), StatusCodes.Status200OK, "application/json")); + } } diff --git a/src/Http/Http.Results/src/Problem.cs b/src/Http/Http.Results/src/Problem.cs index 6c03fd599169..102f08cea968 100644 --- a/src/Http/Http.Results/src/Problem.cs +++ b/src/Http/Http.Results/src/Problem.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -11,8 +12,10 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write Problem Details /// HTTP API responses based on https://tools.ietf.org/html/rfc7807 /// -public sealed class Problem : IResult +public sealed class Problem : IResult, IEndpointMetadataProvider { + private static readonly int _defaultStatusCode = GetDefaultStatusCode(); + /// /// Creates a new instance with /// the provided . @@ -57,4 +60,17 @@ public Task ExecuteAsync(HttpContext httpContext) value: ProblemDetails, ContentType); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(ProblemDetails), _defaultStatusCode, "application/json")); + } + + private static int GetDefaultStatusCode() + { + var problemDetails = new ProblemDetails(); + HttpResultsHelper.ApplyProblemDetailsDefaults(problemDetails, statusCode: null); + return problemDetails.Status ??= StatusCodes.Status500InternalServerError; + } } diff --git a/src/Http/Http.Results/src/Unauthorized.cs b/src/Http/Http.Results/src/Unauthorized.cs index cabd9202f1b2..305b04db3fab 100644 --- a/src/Http/Http.Results/src/Unauthorized.cs +++ b/src/Http/Http.Results/src/Unauthorized.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// Represents an that when executed will /// produce an HTTP response with the No Unauthorized (401) status code. /// -public sealed class Unauthorized : IResult +public sealed class Unauthorized : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class. @@ -37,4 +38,9 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status401Unauthorized)); + } } diff --git a/src/Http/Http.Results/src/UnprocessableEntity.cs b/src/Http/Http.Results/src/UnprocessableEntity.cs index 4a763a46e656..2917c0c7233a 100644 --- a/src/Http/Http.Results/src/UnprocessableEntity.cs +++ b/src/Http/Http.Results/src/UnprocessableEntity.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Unprocessable Entity (422) status code. /// -public sealed class UnprocessableEntity : IResult +public sealed class UnprocessableEntity : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -35,4 +36,10 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status422UnprocessableEntity)); + } } diff --git a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs index 6ff4a5d87b1e..ce779f7469b0 100644 --- a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs +++ b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that on execution will write an object to the response /// with Unprocessable Entity (422) status code. /// -public sealed class UnprocessableEntity : IResult +public sealed class UnprocessableEntity : IResult, IEndpointMetadataProvider { /// /// Initializes a new instance of the class with the values @@ -44,4 +45,10 @@ public Task ExecuteAsync(HttpContext httpContext) logger: logger, Value); } + + /// + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(TValue), StatusCodes.Status422UnprocessableEntity, "application/json")); + } } From 5422e681add5fc0779834b6e12117f6b179102df Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Tue, 12 Apr 2022 11:29:34 -0700 Subject: [PATCH 13/35] WIP WIP --- eng/RequiresDelayedBuildProjects.props | 1 + src/Http/samples/MinimalSample/MinimalSample.csproj | 6 ++++++ src/Http/samples/MinimalSample/Program.cs | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/eng/RequiresDelayedBuildProjects.props b/eng/RequiresDelayedBuildProjects.props index 0951a943c555..a71e43db8269 100644 --- a/eng/RequiresDelayedBuildProjects.props +++ b/eng/RequiresDelayedBuildProjects.props @@ -16,5 +16,6 @@ + diff --git a/src/Http/samples/MinimalSample/MinimalSample.csproj b/src/Http/samples/MinimalSample/MinimalSample.csproj index eea90b96520b..0f2526083adc 100644 --- a/src/Http/samples/MinimalSample/MinimalSample.csproj +++ b/src/Http/samples/MinimalSample/MinimalSample.csproj @@ -2,6 +2,11 @@ $(DefaultNetCoreTargetFramework) + + true + + + true @@ -13,6 +18,7 @@ + diff --git a/src/Http/samples/MinimalSample/Program.cs b/src/Http/samples/MinimalSample/Program.cs index 1324f8ab8fa2..9e51fee2845a 100644 --- a/src/Http/samples/MinimalSample/Program.cs +++ b/src/Http/samples/MinimalSample/Program.cs @@ -4,10 +4,17 @@ using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; -var app = WebApplication.Create(args); +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); if (app.Environment.IsDevelopment()) { + app.MapSwagger(); + app.UseSwaggerUI(); app.UseDeveloperExceptionPage(); } From 0db5208df160b115bd58dafce6bfb1c4baa795ae Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Tue, 12 Apr 2022 17:56:26 -0700 Subject: [PATCH 14/35] React to API review & misc clean-up - Reinstate the `HttpResult` suffix on IResult types except for where the short name has recognized value, e.g. those types that implement `IEndpointMetadataProvider` and will be used in conjunction with `Results` - Order `using` statements before `namespace` declarations - Change from `Results.Typed.xxx` to `TypedResults.xxx` - Added `HttpResults.ValidationProblem` type that represents 400 responses with validation errors (equiv to `BadRequest` - Changed `TypedResults.ValidationProblem` to return new `HttpResults.ValidationProblem` type - Moved `Results` types into the `Microsoft.AspNetCore.Http.HttpResults` namespace to match where the other results types are --- src/Http/Http.Results/src/Accepted.cs | 5 +- src/Http/Http.Results/src/AcceptedAtRoute.cs | 5 +- .../Http.Results/src/AcceptedAtRouteOfT.cs | 6 +- src/Http/Http.Results/src/AcceptedOfT.cs | 5 +- src/Http/Http.Results/src/BadRequest.cs | 4 +- src/Http/Http.Results/src/BadRequestOfT.cs | 5 +- .../{Challenge.cs => ChallengeHttpResult.cs} | 26 +- src/Http/Http.Results/src/Conflict.cs | 4 +- src/Http/Http.Results/src/ConflictOfT.cs | 5 +- .../src/{Content.cs => ContentHttpResult.cs} | 16 +- src/Http/Http.Results/src/Created.cs | 4 +- src/Http/Http.Results/src/CreatedAtRoute.cs | 4 +- .../Http.Results/src/CreatedAtRouteOfT.cs | 5 +- src/Http/Http.Results/src/CreatedOfT.cs | 5 +- .../src/{Empty.cs => EmptyHttpResult.cs} | 8 +- ...ileContent.cs => FileContentHttpResult.cs} | 14 +- ...pFileStream.cs => FileStreamHttpResult.cs} | 14 +- .../src/{Forbid.cs => ForbidHttpResult.cs} | 26 +- .../src/{Json.cs => JsonHttpResultOfT.cs} | 10 +- src/Http/Http.Results/src/NoContent.cs | 4 +- src/Http/Http.Results/src/NotFound.cs | 4 +- src/Http/Http.Results/src/NotFoundOfT.cs | 5 +- src/Http/Http.Results/src/Ok.cs | 5 +- src/Http/Http.Results/src/OkOfT.cs | 6 +- ...sicalFile.cs => PhysicalFileHttpResult.cs} | 16 +- .../src/{Problem.cs => ProblemHttpResult.cs} | 30 +- .../Http.Results/src/PublicAPI.Unshipped.txt | 2 +- ...{PushStream.cs => PushStreamHttpResult.cs} | 14 +- .../{Redirect.cs => RedirectHttpResult.cs} | 18 +- ...oRoute.cs => RedirectToRouteHttpResult.cs} | 30 +- src/Http/Http.Results/src/Results.cs | 48 +- .../src/ResultsCache.StatusCodes.cs | 128 +- .../src/ResultsCache.StatusCodes.tt | 8 +- src/Http/Http.Results/src/ResultsCache.cs | 2 +- src/Http/Http.Results/src/ResultsOfT.cs | 2 +- .../src/{SignIn.cs => SignInHttpResult.cs} | 10 +- .../src/{SignOut.cs => SignOutHttpResult.cs} | 26 +- .../{Status.cs => StatusCodeHttpResult.cs} | 6 +- src/Http/Http.Results/src/TypedResults.cs | 1536 +++++++++-------- ...uthorized.cs => UnauthorizedHttpResult.cs} | 18 +- .../Http.Results/src/UnprocessableEntity.cs | 4 +- .../src/UnprocessableEntityOfT.cs | 5 +- .../Http.Results/src/ValidationProblem.cs | 62 + ...irtualFile.cs => VirtualFileHttpResult.cs} | 14 +- .../Http.Results/test/ChallengeResultTests.cs | 4 +- .../Http.Results/test/ContentResultTests.cs | 4 +- .../Http.Results/test/EmptyResultTests.cs | 2 +- .../test/FileContentResultTests.cs | 2 +- .../Http.Results/test/ForbidResultTests.cs | 8 +- .../test/HttpFileStreamResultTests.cs | 8 +- src/Http/Http.Results/test/JsonResultTests.cs | 16 +- .../test/LocalRedirectResultTests.cs | 12 +- .../test/PhysicalFileResultTest.cs | 2 +- .../Http.Results/test/ProblemResultTests.cs | 6 +- .../test/PushStreamResultTests.cs | 6 +- .../Http.Results/test/RedirectResultTests.cs | 4 +- .../test/RedirectToRouteResultTests.cs | 8 +- .../Http.Results/test/SignInResultTests.cs | 6 +- .../Http.Results/test/SignOutResultTests.cs | 6 +- .../test/StatusCodeResultTests.cs | 2 +- .../test/UnauthorizedResultTests.cs | 4 +- .../test/VirtualFileResultTests.cs | 2 +- .../tools/ResultsOfTGenerator/Program.cs | 2 +- src/Http/samples/MinimalSample/Program.cs | 5 +- 64 files changed, 1165 insertions(+), 1118 deletions(-) rename src/Http/Http.Results/src/{Challenge.cs => ChallengeHttpResult.cs} (80%) rename src/Http/Http.Results/src/{Content.cs => ContentHttpResult.cs} (84%) rename src/Http/Http.Results/src/{Empty.cs => EmptyHttpResult.cs} (70%) rename src/Http/Http.Results/src/{FileContent.cs => FileContentHttpResult.cs} (90%) rename src/Http/Http.Results/src/{HttpFileStream.cs => FileStreamHttpResult.cs} (91%) rename src/Http/Http.Results/src/{Forbid.cs => ForbidHttpResult.cs} (80%) rename src/Http/Http.Results/src/{Json.cs => JsonHttpResultOfT.cs} (88%) rename src/Http/Http.Results/src/{PhysicalFile.cs => PhysicalFileHttpResult.cs} (92%) rename src/Http/Http.Results/src/{Problem.cs => ProblemHttpResult.cs} (64%) rename src/Http/Http.Results/src/{PushStream.cs => PushStreamHttpResult.cs} (90%) rename src/Http/Http.Results/src/{Redirect.cs => RedirectHttpResult.cs} (86%) rename src/Http/Http.Results/src/{RedirectToRoute.cs => RedirectToRouteHttpResult.cs} (92%) rename src/Http/Http.Results/src/{SignIn.cs => SignInHttpResult.cs} (87%) rename src/Http/Http.Results/src/{SignOut.cs => SignOutHttpResult.cs} (80%) rename src/Http/Http.Results/src/{Status.cs => StatusCodeHttpResult.cs} (89%) rename src/Http/Http.Results/src/{Unauthorized.cs => UnauthorizedHttpResult.cs} (76%) create mode 100644 src/Http/Http.Results/src/ValidationProblem.cs rename src/Http/Http.Results/src/{VirtualFile.cs => VirtualFileHttpResult.cs} (92%) diff --git a/src/Http/Http.Results/src/Accepted.cs b/src/Http/Http.Results/src/Accepted.cs index fffc539461d2..60961249ab15 100644 --- a/src/Http/Http.Results/src/Accepted.cs +++ b/src/Http/Http.Results/src/Accepted.cs @@ -1,13 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - -using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with status code Accepted (202) and Location header. diff --git a/src/Http/Http.Results/src/AcceptedAtRoute.cs b/src/Http/Http.Results/src/AcceptedAtRoute.cs index e2aa3d5799ce..e642bbae6eea 100644 --- a/src/Http/Http.Results/src/AcceptedAtRoute.cs +++ b/src/Http/Http.Results/src/AcceptedAtRoute.cs @@ -1,14 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - -using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with status code Accepted (202) and Location header. diff --git a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs index 0df45dea313a..d440d043f7bd 100644 --- a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs @@ -1,19 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - -using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with status code Accepted (202) and Location header. /// Targets a registered route. /// +/// The type of object that will be JSON serialized to the response body. public sealed class AcceptedAtRoute : IResult, IEndpointMetadataProvider { /// diff --git a/src/Http/Http.Results/src/AcceptedOfT.cs b/src/Http/Http.Results/src/AcceptedOfT.cs index 0f971389a3f1..4cd8c48cddfc 100644 --- a/src/Http/Http.Results/src/AcceptedOfT.cs +++ b/src/Http/Http.Results/src/AcceptedOfT.cs @@ -1,13 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - -using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with status code Accepted (202) and Location header. diff --git a/src/Http/Http.Results/src/BadRequest.cs b/src/Http/Http.Results/src/BadRequest.cs index 536b3384d907..01621b2138cf 100644 --- a/src/Http/Http.Results/src/BadRequest.cs +++ b/src/Http/Http.Results/src/BadRequest.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Bad Request (400) status code. diff --git a/src/Http/Http.Results/src/BadRequestOfT.cs b/src/Http/Http.Results/src/BadRequestOfT.cs index be1a9358acd2..2e044c85afa9 100644 --- a/src/Http/Http.Results/src/BadRequestOfT.cs +++ b/src/Http/Http.Results/src/BadRequestOfT.cs @@ -1,16 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Bad Request (400) status code. /// +/// The type of error object that will be JSON serialized to the response body. public sealed class BadRequest : IResult, IEndpointMetadataProvider { /// diff --git a/src/Http/Http.Results/src/Challenge.cs b/src/Http/Http.Results/src/ChallengeHttpResult.cs similarity index 80% rename from src/Http/Http.Results/src/Challenge.cs rename to src/Http/Http.Results/src/ChallengeHttpResult.cs index dcbe244fd7ca..1772c6f0d379 100644 --- a/src/Http/Http.Results/src/Challenge.cs +++ b/src/Http/Http.Results/src/ChallengeHttpResult.cs @@ -11,67 +11,67 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that on execution invokes . /// -public sealed partial class Challenge : IResult +public sealed partial class ChallengeHttpResult : IResult { /// - /// Initializes a new instance of . + /// Initializes a new instance of . /// - internal Challenge() + internal ChallengeHttpResult() : this(Array.Empty()) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme. /// /// The authentication scheme to challenge. - internal Challenge(string authenticationScheme) + internal ChallengeHttpResult(string authenticationScheme) : this(new[] { authenticationScheme }) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes. /// /// The authentication schemes to challenge. - internal Challenge(IList authenticationSchemes) + internal ChallengeHttpResult(IList authenticationSchemes) : this(authenticationSchemes, properties: null) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified . /// /// used to perform the authentication /// challenge. - internal Challenge(AuthenticationProperties? properties) + internal ChallengeHttpResult(AuthenticationProperties? properties) : this(Array.Empty(), properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme and . /// /// The authentication schemes to challenge. /// used to perform the authentication /// challenge. - internal Challenge(string authenticationScheme, AuthenticationProperties? properties) + internal ChallengeHttpResult(string authenticationScheme, AuthenticationProperties? properties) : this(new[] { authenticationScheme }, properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes and . /// /// The authentication scheme to challenge. /// used to perform the authentication /// challenge. - internal Challenge(IList authenticationSchemes, AuthenticationProperties? properties) + internal ChallengeHttpResult(IList authenticationSchemes, AuthenticationProperties? properties) { AuthenticationSchemes = authenticationSchemes.AsReadOnly(); Properties = properties; diff --git a/src/Http/Http.Results/src/Conflict.cs b/src/Http/Http.Results/src/Conflict.cs index 39183233c44f..61e7c9f6aa47 100644 --- a/src/Http/Http.Results/src/Conflict.cs +++ b/src/Http/Http.Results/src/Conflict.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Conflict (409) status code. diff --git a/src/Http/Http.Results/src/ConflictOfT.cs b/src/Http/Http.Results/src/ConflictOfT.cs index bf5f5805ed83..9c31eae8fd9e 100644 --- a/src/Http/Http.Results/src/ConflictOfT.cs +++ b/src/Http/Http.Results/src/ConflictOfT.cs @@ -1,16 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Conflict (409) status code. /// +/// The type of object that will be JSON serialized to the response body. public sealed class Conflict : IResult, IEndpointMetadataProvider { /// diff --git a/src/Http/Http.Results/src/Content.cs b/src/Http/Http.Results/src/ContentHttpResult.cs similarity index 84% rename from src/Http/Http.Results/src/Content.cs rename to src/Http/Http.Results/src/ContentHttpResult.cs index bbf09845ca25..8beaf09f01c9 100644 --- a/src/Http/Http.Results/src/Content.cs +++ b/src/Http/Http.Results/src/ContentHttpResult.cs @@ -1,34 +1,34 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// -/// An that when executed +/// An that when executed /// will produce a response with content. /// -public sealed partial class Content : IResult +public sealed partial class ContentHttpResult : IResult { /// - /// Initializes a new instance of the class with the values. + /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. /// The Content-Type header for the response - internal Content(string? content, string? contentType) + internal ContentHttpResult(string? content, string? contentType) : this(content, contentType, statusCode: null) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// /// The value to format in the entity body. /// The HTTP status code of the response. /// The Content-Type header for the response - internal Content(string? content, string? contentType, int? statusCode) + internal ContentHttpResult(string? content, string? contentType, int? statusCode) { ResponseContent = content; StatusCode = statusCode; diff --git a/src/Http/Http.Results/src/Created.cs b/src/Http/Http.Results/src/Created.cs index b082d27bf529..30333e52f5d7 100644 --- a/src/Http/Http.Results/src/Created.cs +++ b/src/Http/Http.Results/src/Created.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with status code Created (201) and Location header. diff --git a/src/Http/Http.Results/src/CreatedAtRoute.cs b/src/Http/Http.Results/src/CreatedAtRoute.cs index 4a64e2afa203..67eb7516eebc 100644 --- a/src/Http/Http.Results/src/CreatedAtRoute.cs +++ b/src/Http/Http.Results/src/CreatedAtRoute.cs @@ -1,13 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with status code Created (201) and Location header. diff --git a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs index ddf14c0295d1..e3240b16032e 100644 --- a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs @@ -1,18 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with status code Created (201) and Location header. /// Targets a registered route. /// +/// The type of object that will be JSON serialized to the response body. public sealed class CreatedAtRoute : IResult, IEndpointMetadataProvider { /// diff --git a/src/Http/Http.Results/src/CreatedOfT.cs b/src/Http/Http.Results/src/CreatedOfT.cs index 21f21ea56809..38b3eed4da7c 100644 --- a/src/Http/Http.Results/src/CreatedOfT.cs +++ b/src/Http/Http.Results/src/CreatedOfT.cs @@ -1,16 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with status code Created (201) and Location header. /// +/// The type of object that will be JSON serialized to the response body. public sealed class Created : IResult, IEndpointMetadataProvider { /// diff --git a/src/Http/Http.Results/src/Empty.cs b/src/Http/Http.Results/src/EmptyHttpResult.cs similarity index 70% rename from src/Http/Http.Results/src/Empty.cs rename to src/Http/Http.Results/src/EmptyHttpResult.cs index e4bbaf9080dc..ccdc3bd05984 100644 --- a/src/Http/Http.Results/src/Empty.cs +++ b/src/Http/Http.Results/src/EmptyHttpResult.cs @@ -7,16 +7,16 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// Represents an that when executed will /// do nothing. /// -public sealed class Empty : IResult +public sealed class EmptyHttpResult : IResult { - private Empty() + private EmptyHttpResult() { } /// - /// Gets an instance of . + /// Gets an instance of . /// - public static Empty Instance { get; } = new(); + public static EmptyHttpResult Instance { get; } = new(); /// public Task ExecuteAsync(HttpContext httpContext) diff --git a/src/Http/Http.Results/src/FileContent.cs b/src/Http/Http.Results/src/FileContentHttpResult.cs similarity index 90% rename from src/Http/Http.Results/src/FileContent.cs rename to src/Http/Http.Results/src/FileContentHttpResult.cs index d3f8a31677ab..960836b99479 100644 --- a/src/Http/Http.Results/src/FileContent.cs +++ b/src/Http/Http.Results/src/FileContentHttpResult.cs @@ -12,29 +12,29 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// Represents an that when executed will /// write a file from the content to the response. /// -public sealed partial class FileContent : IResult +public sealed partial class FileContentHttpResult : IResult { /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the /// provided . /// /// The bytes that represent the file contents. /// The Content-Type of the file. - internal FileContent(ReadOnlyMemory fileContents, string? contentType) + internal FileContentHttpResult(ReadOnlyMemory fileContents, string? contentType) : this(fileContents, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The bytes that represent the file contents. /// The Content-Type header of the response. /// The suggested file name. - internal FileContent( + internal FileContentHttpResult( ReadOnlyMemory fileContents, string? contentType, string? fileDownloadName) @@ -43,7 +43,7 @@ internal FileContent( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The bytes that represent the file contents. /// The Content-Type of the file. @@ -51,7 +51,7 @@ internal FileContent( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal FileContent( + internal FileContentHttpResult( ReadOnlyMemory fileContents, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/src/HttpFileStream.cs b/src/Http/Http.Results/src/FileStreamHttpResult.cs similarity index 91% rename from src/Http/Http.Results/src/HttpFileStream.cs rename to src/Http/Http.Results/src/FileStreamHttpResult.cs index c349f785d901..eff283d20d2d 100644 --- a/src/Http/Http.Results/src/HttpFileStream.cs +++ b/src/Http/Http.Results/src/FileStreamHttpResult.cs @@ -12,29 +12,29 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// Represents an that when executed will /// write a file from a stream to the response. /// -public sealed class HttpFileStream : IResult +public sealed class FileStreamHttpResult : IResult { /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the /// provided . /// /// The stream with the file. /// The Content-Type of the file. - internal HttpFileStream(Stream fileStream, string? contentType) + internal FileStreamHttpResult(Stream fileStream, string? contentType) : this(fileStream, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The stream with the file. /// The Content-Type header of the response. /// The suggested file name. - internal HttpFileStream( + internal FileStreamHttpResult( Stream fileStream, string? contentType, string? fileDownloadName) @@ -43,7 +43,7 @@ internal HttpFileStream( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The stream with the file. /// The Content-Type of the file. @@ -51,7 +51,7 @@ internal HttpFileStream( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal HttpFileStream( + internal FileStreamHttpResult( Stream fileStream, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/src/Forbid.cs b/src/Http/Http.Results/src/ForbidHttpResult.cs similarity index 80% rename from src/Http/Http.Results/src/Forbid.cs rename to src/Http/Http.Results/src/ForbidHttpResult.cs index d76be06654ba..5afdb53b85d2 100644 --- a/src/Http/Http.Results/src/Forbid.cs +++ b/src/Http/Http.Results/src/ForbidHttpResult.cs @@ -11,67 +11,67 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that on execution invokes . /// -public sealed partial class Forbid : IResult +public sealed partial class ForbidHttpResult : IResult { /// - /// Initializes a new instance of . + /// Initializes a new instance of . /// - internal Forbid() + internal ForbidHttpResult() : this(Array.Empty()) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme. /// /// The authentication scheme to challenge. - internal Forbid(string authenticationScheme) + internal ForbidHttpResult(string authenticationScheme) : this(new[] { authenticationScheme }) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes. /// /// The authentication schemes to challenge. - internal Forbid(IList authenticationSchemes) + internal ForbidHttpResult(IList authenticationSchemes) : this(authenticationSchemes, properties: null) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified . /// /// used to perform the authentication /// challenge. - internal Forbid(AuthenticationProperties? properties) + internal ForbidHttpResult(AuthenticationProperties? properties) : this(Array.Empty(), properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme and . /// /// The authentication schemes to challenge. /// used to perform the authentication /// challenge. - internal Forbid(string authenticationScheme, AuthenticationProperties? properties) + internal ForbidHttpResult(string authenticationScheme, AuthenticationProperties? properties) : this(new[] { authenticationScheme }, properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes and . /// /// The authentication scheme to challenge. /// used to perform the authentication /// challenge. - internal Forbid(IList authenticationSchemes, AuthenticationProperties? properties) + internal ForbidHttpResult(IList authenticationSchemes, AuthenticationProperties? properties) { AuthenticationSchemes = authenticationSchemes.AsReadOnly(); Properties = properties; diff --git a/src/Http/Http.Results/src/Json.cs b/src/Http/Http.Results/src/JsonHttpResultOfT.cs similarity index 88% rename from src/Http/Http.Results/src/Json.cs rename to src/Http/Http.Results/src/JsonHttpResultOfT.cs index 2474623f7ffe..dec845ac206a 100644 --- a/src/Http/Http.Results/src/Json.cs +++ b/src/Http/Http.Results/src/JsonHttpResultOfT.cs @@ -11,14 +11,14 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An action result which formats the given object as JSON. /// -public sealed partial class Json : IResult +public sealed partial class JsonHttpResult : IResult { /// /// Initializes a new instance of the class with the values. /// /// The value to format in the entity body. /// The serializer settings. - internal Json(TValue? value, JsonSerializerOptions? jsonSerializerOptions) + internal JsonHttpResult(TValue? value, JsonSerializerOptions? jsonSerializerOptions) : this(value, statusCode: null, contentType: null, jsonSerializerOptions: jsonSerializerOptions) { } @@ -29,7 +29,7 @@ internal Json(TValue? value, JsonSerializerOptions? jsonSerializerOptions) /// The value to format in the entity body. /// The HTTP status code of the response. /// The serializer settings. - internal Json(TValue? value, int? statusCode, JsonSerializerOptions? jsonSerializerOptions) + internal JsonHttpResult(TValue? value, int? statusCode, JsonSerializerOptions? jsonSerializerOptions) : this(value, statusCode: statusCode, contentType: null, jsonSerializerOptions: jsonSerializerOptions) { } @@ -40,7 +40,7 @@ internal Json(TValue? value, int? statusCode, JsonSerializerOptions? jsonSeriali /// The value to format in the entity body. /// The value for the Content-Type header /// The serializer settings. - internal Json(TValue? value, string? contentType, JsonSerializerOptions? jsonSerializerOptions) + internal JsonHttpResult(TValue? value, string? contentType, JsonSerializerOptions? jsonSerializerOptions) : this(value, statusCode: null, contentType: contentType, jsonSerializerOptions: jsonSerializerOptions) { @@ -53,7 +53,7 @@ internal Json(TValue? value, string? contentType, JsonSerializerOptions? jsonSer /// The HTTP status code of the response. /// The serializer settings. /// The value for the Content-Type header - internal Json(TValue? value, int? statusCode, string? contentType, JsonSerializerOptions? jsonSerializerOptions) + internal JsonHttpResult(TValue? value, int? statusCode, string? contentType, JsonSerializerOptions? jsonSerializerOptions) { Value = value; JsonSerializerOptions = jsonSerializerOptions; diff --git a/src/Http/Http.Results/src/NoContent.cs b/src/Http/Http.Results/src/NoContent.cs index 15a41e82f21b..4a718b45f925 100644 --- a/src/Http/Http.Results/src/NoContent.cs +++ b/src/Http/Http.Results/src/NoContent.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// Represents an that when executed will /// produce an HTTP response with the No Content (204) status code. diff --git a/src/Http/Http.Results/src/NotFound.cs b/src/Http/Http.Results/src/NotFound.cs index 7a73995e95f4..2d4ed5876c1f 100644 --- a/src/Http/Http.Results/src/NotFound.cs +++ b/src/Http/Http.Results/src/NotFound.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Not Found (404) status code. diff --git a/src/Http/Http.Results/src/NotFoundOfT.cs b/src/Http/Http.Results/src/NotFoundOfT.cs index 64a50640eaed..2516079814d7 100644 --- a/src/Http/Http.Results/src/NotFoundOfT.cs +++ b/src/Http/Http.Results/src/NotFoundOfT.cs @@ -1,16 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Not Found (404) status code. /// +/// The type of object that will be JSON serialized to the response body. public sealed class NotFound : IResult, IEndpointMetadataProvider { /// diff --git a/src/Http/Http.Results/src/Ok.cs b/src/Http/Http.Results/src/Ok.cs index 9d59cac5f5c8..f3c6ab9cec50 100644 --- a/src/Http/Http.Results/src/Ok.cs +++ b/src/Http/Http.Results/src/Ok.cs @@ -1,13 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - -using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Ok (200) status code. diff --git a/src/Http/Http.Results/src/OkOfT.cs b/src/Http/Http.Results/src/OkOfT.cs index 7506a79d08d0..c2b8fef133bf 100644 --- a/src/Http/Http.Results/src/OkOfT.cs +++ b/src/Http/Http.Results/src/OkOfT.cs @@ -1,17 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - -using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Ok (200) status code. /// +/// The type of object that will be JSON serialized to the response body. public sealed class Ok : IResult, IEndpointMetadataProvider { /// diff --git a/src/Http/Http.Results/src/PhysicalFile.cs b/src/Http/Http.Results/src/PhysicalFileHttpResult.cs similarity index 92% rename from src/Http/Http.Results/src/PhysicalFile.cs rename to src/Http/Http.Results/src/PhysicalFileHttpResult.cs index ecbff3d8c46f..4e69b71a88f6 100644 --- a/src/Http/Http.Results/src/PhysicalFile.cs +++ b/src/Http/Http.Results/src/PhysicalFileHttpResult.cs @@ -8,31 +8,31 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// -/// A on execution will write a file from disk to the response +/// A on execution will write a file from disk to the response /// using mechanisms provided by the host. /// -public sealed partial class PhysicalFile : IResult +public sealed partial class PhysicalFileHttpResult : IResult { /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. - internal PhysicalFile(string fileName, string? contentType) + internal PhysicalFileHttpResult(string fileName, string? contentType) : this(fileName, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. /// The suggested file name. - internal PhysicalFile( + internal PhysicalFileHttpResult( string fileName, string? contentType, string? fileDownloadName) @@ -41,7 +41,7 @@ internal PhysicalFile( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. @@ -49,7 +49,7 @@ internal PhysicalFile( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal PhysicalFile( + internal PhysicalFileHttpResult( string fileName, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/src/Problem.cs b/src/Http/Http.Results/src/ProblemHttpResult.cs similarity index 64% rename from src/Http/Http.Results/src/Problem.cs rename to src/Http/Http.Results/src/ProblemHttpResult.cs index 102f08cea968..7837fa4c6927 100644 --- a/src/Http/Http.Results/src/Problem.cs +++ b/src/Http/Http.Results/src/ProblemHttpResult.cs @@ -1,27 +1,24 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - -using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write Problem Details /// HTTP API responses based on https://tools.ietf.org/html/rfc7807 /// -public sealed class Problem : IResult, IEndpointMetadataProvider +public sealed class ProblemHttpResult : IResult { - private static readonly int _defaultStatusCode = GetDefaultStatusCode(); - /// - /// Creates a new instance with + /// Creates a new instance with /// the provided . /// /// The instance to format in the entity body. - internal Problem(ProblemDetails problemDetails) + internal ProblemHttpResult(ProblemDetails problemDetails) { ProblemDetails = problemDetails; HttpResultsHelper.ApplyProblemDetailsDefaults(ProblemDetails, statusCode: null); @@ -33,7 +30,7 @@ internal Problem(ProblemDetails problemDetails) public ProblemDetails ProblemDetails { get; } /// - /// Gets or sets the value for the Content-Type header. + /// Gets the value for the Content-Type header. /// public string ContentType => "application/problem+json"; @@ -46,7 +43,7 @@ internal Problem(ProblemDetails problemDetails) public Task ExecuteAsync(HttpContext httpContext) { var loggerFactory = httpContext.RequestServices.GetRequiredService(); - var logger = loggerFactory.CreateLogger(typeof(Problem)); + var logger = loggerFactory.CreateLogger(typeof(ProblemHttpResult)); if (StatusCode is { } code) { @@ -60,17 +57,4 @@ public Task ExecuteAsync(HttpContext httpContext) value: ProblemDetails, ContentType); } - - /// - static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) - { - context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(ProblemDetails), _defaultStatusCode, "application/json")); - } - - private static int GetDefaultStatusCode() - { - var problemDetails = new ProblemDetails(); - HttpResultsHelper.ApplyProblemDetailsDefaults(problemDetails, statusCode: null); - return problemDetails.Status ??= StatusCodes.Status500InternalServerError; - } } diff --git a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt index 3d6320905c3c..c6243c6aa0f7 100644 --- a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt @@ -238,7 +238,7 @@ static Microsoft.AspNetCore.Http.Results.Typed.Text(string! content, string? con static Microsoft.AspNetCore.Http.Results.Typed.Unauthorized() -> Microsoft.AspNetCore.Http.HttpResults.Unauthorized! static Microsoft.AspNetCore.Http.Results.Typed.UnprocessableEntity() -> Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity! static Microsoft.AspNetCore.Http.Results.Typed.UnprocessableEntity(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity! -static Microsoft.AspNetCore.Http.Results.Typed.ValidationProblem(System.Collections.Generic.IDictionary! errors, string? detail = null, string? instance = null, int? statusCode = null, string? title = null, string? type = null, System.Collections.Generic.IDictionary? extensions = null) -> Microsoft.AspNetCore.Http.HttpResults.Problem! +static Microsoft.AspNetCore.Http.Results.Typed.ValidationProblem(System.Collections.Generic.IDictionary! errors, string? detail = null, string? instance = null, string? title = null, string? type = null, System.Collections.Generic.IDictionary? extensions = null) -> Microsoft.AspNetCore.Http.HttpResults.BadRequest! static Microsoft.AspNetCore.Http.Results.Typed.VirtualFile(string! path, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.VirtualFile! static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.Results! static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.Results! diff --git a/src/Http/Http.Results/src/PushStream.cs b/src/Http/Http.Results/src/PushStreamHttpResult.cs similarity index 90% rename from src/Http/Http.Results/src/PushStream.cs rename to src/Http/Http.Results/src/PushStreamHttpResult.cs index d7bac2daf7fc..e7d3e852788b 100644 --- a/src/Http/Http.Results/src/PushStream.cs +++ b/src/Http/Http.Results/src/PushStreamHttpResult.cs @@ -11,30 +11,30 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// Represents an that when executed will /// write a file from the writer callback to the response. /// -public sealed class PushStream : IResult +public sealed class PushStreamHttpResult : IResult { private readonly Func _streamWriterCallback; /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the provided . /// /// The stream writer callback. /// The Content-Type header of the response. - internal PushStream(Func streamWriterCallback, string? contentType) + internal PushStreamHttpResult(Func streamWriterCallback, string? contentType) : this(streamWriterCallback, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The stream writer callback. /// The Content-Type header of the response. /// The suggested file name. - internal PushStream( + internal PushStreamHttpResult( Func streamWriterCallback, string? contentType, string? fileDownloadName) @@ -43,7 +43,7 @@ internal PushStream( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The stream writer callback. /// The Content-Type header of the response. @@ -51,7 +51,7 @@ internal PushStream( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal PushStream( + internal PushStreamHttpResult( Func streamWriterCallback, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/src/Redirect.cs b/src/Http/Http.Results/src/RedirectHttpResult.cs similarity index 86% rename from src/Http/Http.Results/src/Redirect.cs rename to src/Http/Http.Results/src/RedirectHttpResult.cs index 510d12937f51..e466cef62dcd 100644 --- a/src/Http/Http.Results/src/Redirect.cs +++ b/src/Http/Http.Results/src/RedirectHttpResult.cs @@ -11,43 +11,43 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// An that returns a Found (302), Moved Permanently (301), Temporary Redirect (307), /// or Permanent Redirect (308) response with a Location header to the supplied URL. /// -public sealed partial class Redirect : IResult +public sealed partial class RedirectHttpResult : IResult { /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The URL to redirect to. - internal Redirect(string url) + internal RedirectHttpResult(string url) : this(url, permanent: false) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The URL to redirect to. /// Specifies whether the redirect should be permanent (301) or temporary (302). - internal Redirect(string url, bool permanent) + internal RedirectHttpResult(string url, bool permanent) : this(url, permanent, preserveMethod: false) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The URL to redirect to. /// Specifies whether the redirect should be permanent (301) or temporary (302). /// If set to true, make the temporary redirect (307) /// or permanent redirect (308) preserve the initial request method. - internal Redirect(string url, bool permanent, bool preserveMethod) + internal RedirectHttpResult(string url, bool permanent, bool preserveMethod) : this(url, acceptLocalUrlOnly: false, permanent, preserveMethod) { } /// - /// Initializes a new instance of the class with the values + /// Initializes a new instance of the class with the values /// provided. /// /// The URL to redirect to. @@ -56,7 +56,7 @@ internal Redirect(string url, bool permanent, bool preserveMethod) /// or permanent redirect (308) preserve the initial request method. /// If set to true, only local URLs are accepted /// and will throw an exception when the supplied URL is not considered local. - internal Redirect(string url, bool acceptLocalUrlOnly, bool permanent, bool preserveMethod) + internal RedirectHttpResult(string url, bool acceptLocalUrlOnly, bool permanent, bool preserveMethod) { if (url == null) { diff --git a/src/Http/Http.Results/src/RedirectToRoute.cs b/src/Http/Http.Results/src/RedirectToRouteHttpResult.cs similarity index 92% rename from src/Http/Http.Results/src/RedirectToRoute.cs rename to src/Http/Http.Results/src/RedirectToRouteHttpResult.cs index af3ec08cc004..a846f56dd3c4 100644 --- a/src/Http/Http.Results/src/RedirectToRoute.cs +++ b/src/Http/Http.Results/src/RedirectToRouteHttpResult.cs @@ -12,25 +12,25 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// or Permanent Redirect (308) response with a Location header. /// Targets a registered route. /// -public sealed partial class RedirectToRoute : IResult +public sealed partial class RedirectToRouteHttpResult : IResult { /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The parameters for the route. - internal RedirectToRoute(object? routeValues) + internal RedirectToRouteHttpResult(object? routeValues) : this(routeName: null, routeValues: routeValues) { } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. /// The parameters for the route. - internal RedirectToRoute( + internal RedirectToRouteHttpResult( string? routeName, object? routeValues) : this(routeName, routeValues, permanent: false) @@ -38,14 +38,14 @@ internal RedirectToRoute( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. /// The parameters for the route. /// If set to true, makes the redirect permanent (301). /// Otherwise a temporary redirect is used (302). - internal RedirectToRoute( + internal RedirectToRouteHttpResult( string? routeName, object? routeValues, bool permanent) @@ -54,7 +54,7 @@ internal RedirectToRoute( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. @@ -63,7 +63,7 @@ internal RedirectToRoute( /// Otherwise a temporary redirect is used (302). /// If set to true, make the temporary redirect (307) /// or permanent redirect (308) preserve the initial request method. - internal RedirectToRoute( + internal RedirectToRouteHttpResult( string? routeName, object? routeValues, bool permanent, @@ -73,13 +73,13 @@ internal RedirectToRoute( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. /// The parameters for the route. /// The fragment to add to the URL. - internal RedirectToRoute( + internal RedirectToRouteHttpResult( string? routeName, object? routeValues, string? fragment) @@ -88,7 +88,7 @@ internal RedirectToRoute( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. @@ -96,7 +96,7 @@ internal RedirectToRoute( /// If set to true, makes the redirect permanent (301). /// Otherwise a temporary redirect is used (302). /// The fragment to add to the URL. - internal RedirectToRoute( + internal RedirectToRouteHttpResult( string? routeName, object? routeValues, bool permanent, @@ -106,7 +106,7 @@ internal RedirectToRoute( } /// - /// Initializes a new instance of the with the values + /// Initializes a new instance of the with the values /// provided. /// /// The name of the route. @@ -116,7 +116,7 @@ internal RedirectToRoute( /// If set to true, make the temporary redirect (307) /// or permanent redirect (308) preserve the initial request method. /// The fragment to add to the URL. - internal RedirectToRoute( + internal RedirectToRouteHttpResult( string? routeName, object? routeValues, bool permanent, diff --git a/src/Http/Http.Results/src/Results.cs b/src/Http/Http.Results/src/Results.cs index b062ae3c1c04..edab9a8624e4 100644 --- a/src/Http/Http.Results/src/Results.cs +++ b/src/Http/Http.Results/src/Results.cs @@ -33,7 +33,7 @@ public static partial class Results public static IResult Challenge( AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new Challenge(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + => new ChallengeHttpResult(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); /// /// Creates a that on execution invokes . @@ -51,7 +51,7 @@ public static IResult Challenge( /// a redirect to show a login page. /// public static IResult Forbid(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new Forbid(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + => new ForbidHttpResult(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); /// /// Creates an that on execution invokes . @@ -64,7 +64,7 @@ public static IResult SignIn( ClaimsPrincipal principal, AuthenticationProperties? properties = null, string? authenticationScheme = null) - => new SignIn(principal, authenticationScheme, properties); + => new SignInHttpResult(principal, authenticationScheme, properties); /// /// Creates an that on execution invokes . @@ -73,7 +73,7 @@ public static IResult SignIn( /// The authentication scheme to use for the sign-out operation. /// The created for the response. public static IResult SignOut(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new SignOut(authenticationSchemes ?? Array.Empty(), properties); + => new SignOutHttpResult(authenticationSchemes ?? Array.Empty(), properties); /// /// Writes the string to the HTTP response. @@ -115,7 +115,7 @@ public static IResult Text(string content, string? contentType = null, Encoding? mediaTypeHeaderValue.Encoding = contentEncoding ?? mediaTypeHeaderValue.Encoding; } - return new Content(content, mediaTypeHeaderValue?.ToString()); + return new ContentHttpResult(content, mediaTypeHeaderValue?.ToString()); } /// @@ -125,7 +125,7 @@ public static IResult Text(string content, string? contentType = null, Encoding? /// The content type (MIME type). /// The created object for the response. public static IResult Content(string content, MediaTypeHeaderValue contentType) - => new Content(content, contentType.ToString()); + => new ContentHttpResult(content, contentType.ToString()); /// /// Creates a that serializes the specified object to JSON. @@ -134,12 +134,12 @@ public static IResult Content(string content, MediaTypeHeaderValue contentType) /// The serializer options to use when serializing the value. /// The content-type to set on the response. /// The status code to set on the response. - /// The created that serializes the specified + /// The created that serializes the specified /// as JSON format for the response. /// Callers should cache an instance of serializer settings to avoid /// recreating cached data with each call. public static IResult Json(object? data, JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) - => new Json(data, statusCode, options) + => new JsonHttpResult(data, statusCode, options) { ContentType = contentType, }; @@ -169,7 +169,7 @@ public static IResult File( bool enableRangeProcessing = false, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - => new FileContent(fileContents, contentType) + => new FileContentHttpResult(fileContents, contentType) { FileDownloadName = fileDownloadName, EnableRangeProcessing = enableRangeProcessing, @@ -200,7 +200,7 @@ public static IResult Bytes( bool enableRangeProcessing = false, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - => new FileContent(contents, contentType) + => new FileContentHttpResult(contents, contentType) { FileDownloadName = fileDownloadName, EnableRangeProcessing = enableRangeProcessing, @@ -231,7 +231,7 @@ public static IResult Bytes( bool enableRangeProcessing = false, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - => new FileContent(contents, contentType) + => new FileContentHttpResult(contents, contentType) { FileDownloadName = fileDownloadName, EnableRangeProcessing = enableRangeProcessing, @@ -271,7 +271,7 @@ public static IResult File( EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) { - return new HttpFileStream(fileStream, contentType) + return new FileStreamHttpResult(fileStream, contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -310,7 +310,7 @@ public static IResult Stream( EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) { - return new HttpFileStream(stream, contentType) + return new FileStreamHttpResult(stream, contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -348,7 +348,7 @@ public static IResult Stream( EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) { - return new HttpFileStream(pipeReader.AsStream(), contentType) + return new FileStreamHttpResult(pipeReader.AsStream(), contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -381,7 +381,7 @@ public static IResult Stream( DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) { - return new PushStream(streamWriterCallback, contentType) + return new PushStreamHttpResult(streamWriterCallback, contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -415,7 +415,7 @@ public static IResult File( { if (Path.IsPathRooted(path)) { - return new PhysicalFile(path, contentType) + return new PhysicalFileHttpResult(path, contentType) { FileDownloadName = fileDownloadName, LastModified = lastModified, @@ -425,7 +425,7 @@ public static IResult File( } else { - return new VirtualFile(path, contentType) + return new VirtualFileHttpResult(path, contentType) { FileDownloadName = fileDownloadName, LastModified = lastModified, @@ -449,7 +449,7 @@ public static IResult File( /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. /// The created for the response. public static IResult Redirect(string url, bool permanent = false, bool preserveMethod = false) - => new Redirect(url, permanent, preserveMethod); + => new RedirectHttpResult(url, permanent, preserveMethod); /// /// Redirects to the specified . @@ -465,7 +465,7 @@ public static IResult Redirect(string url, bool permanent = false, bool preserve /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. /// The created for the response. public static IResult LocalRedirect(string localUrl, bool permanent = false, bool preserveMethod = false) - => new Redirect(localUrl, acceptLocalUrlOnly: true, permanent, preserveMethod); + => new RedirectHttpResult(localUrl, acceptLocalUrlOnly: true, permanent, preserveMethod); /// /// Redirects to the specified route. @@ -483,7 +483,7 @@ public static IResult LocalRedirect(string localUrl, bool permanent = false, boo /// The fragment to add to the URL. /// The created for the response. public static IResult RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) - => new RedirectToRoute( + => new RedirectToRouteHttpResult( routeName: routeName, routeValues: routeValues, permanent: permanent, @@ -587,7 +587,7 @@ public static IResult Problem( } } - return new Problem(problemDetails); + return new ProblemHttpResult(problemDetails); } /// @@ -597,7 +597,7 @@ public static IResult Problem( /// The created for the response. public static IResult Problem(ProblemDetails problemDetails) { - return new Problem(problemDetails); + return new ProblemHttpResult(problemDetails); } /// @@ -639,7 +639,7 @@ public static IResult ValidationProblem( } } - return new Problem(problemDetails); + return new ProblemHttpResult(problemDetails); } /// @@ -706,7 +706,7 @@ public static IResult AcceptedAtRoute(string? routeName = null, object? routeVal /// /// Produces an empty result response, that when executed will do nothing. /// - public static IResult Empty { get; } = HttpResults.Empty.Instance; + public static IResult Empty { get; } = HttpResults.EmptyHttpResult.Instance; /// /// Provides a container for external libraries to extend diff --git a/src/Http/Http.Results/src/ResultsCache.StatusCodes.cs b/src/Http/Http.Results/src/ResultsCache.StatusCodes.cs index 394a8da16dd6..0468b7a565e0 100644 --- a/src/Http/Http.Results/src/ResultsCache.StatusCodes.cs +++ b/src/Http/Http.Results/src/ResultsCache.StatusCodes.cs @@ -12,75 +12,75 @@ namespace Microsoft.AspNetCore.Http; [GeneratedCode("TextTemplatingFileGenerator", "")] internal partial class ResultsCache { - private static Status? _status101SwitchingProtocols; - private static Status? _status102Processing; - private static Status? _status200OK; - private static Status? _status201Created; - private static Status? _status202Accepted; - private static Status? _status203NonAuthoritative; - private static Status? _status204NoContent; - private static Status? _status205ResetContent; - private static Status? _status206PartialContent; - private static Status? _status207MultiStatus; - private static Status? _status208AlreadyReported; - private static Status? _status226IMUsed; - private static Status? _status300MultipleChoices; - private static Status? _status301MovedPermanently; - private static Status? _status302Found; - private static Status? _status303SeeOther; - private static Status? _status304NotModified; - private static Status? _status305UseProxy; - private static Status? _status306SwitchProxy; - private static Status? _status307TemporaryRedirect; - private static Status? _status308PermanentRedirect; - private static Status? _status400BadRequest; - private static Status? _status401Unauthorized; - private static Status? _status402PaymentRequired; - private static Status? _status403Forbidden; - private static Status? _status404NotFound; - private static Status? _status405MethodNotAllowed; - private static Status? _status406NotAcceptable; - private static Status? _status407ProxyAuthenticationRequired; - private static Status? _status408RequestTimeout; - private static Status? _status409Conflict; - private static Status? _status410Gone; - private static Status? _status411LengthRequired; - private static Status? _status412PreconditionFailed; - private static Status? _status413RequestEntityTooLarge; - private static Status? _status414RequestUriTooLong; - private static Status? _status415UnsupportedMediaType; - private static Status? _status416RequestedRangeNotSatisfiable; - private static Status? _status417ExpectationFailed; - private static Status? _status418ImATeapot; - private static Status? _status419AuthenticationTimeout; - private static Status? _status421MisdirectedRequest; - private static Status? _status422UnprocessableEntity; - private static Status? _status423Locked; - private static Status? _status424FailedDependency; - private static Status? _status426UpgradeRequired; - private static Status? _status428PreconditionRequired; - private static Status? _status429TooManyRequests; - private static Status? _status431RequestHeaderFieldsTooLarge; - private static Status? _status451UnavailableForLegalReasons; - private static Status? _status500InternalServerError; - private static Status? _status501NotImplemented; - private static Status? _status502BadGateway; - private static Status? _status503ServiceUnavailable; - private static Status? _status504GatewayTimeout; - private static Status? _status505HttpVersionNotsupported; - private static Status? _status506VariantAlsoNegotiates; - private static Status? _status507InsufficientStorage; - private static Status? _status508LoopDetected; - private static Status? _status510NotExtended; - private static Status? _status511NetworkAuthenticationRequired; + private static StatusCodeHttpResult? _status101SwitchingProtocols; + private static StatusCodeHttpResult? _status102Processing; + private static StatusCodeHttpResult? _status200OK; + private static StatusCodeHttpResult? _status201Created; + private static StatusCodeHttpResult? _status202Accepted; + private static StatusCodeHttpResult? _status203NonAuthoritative; + private static StatusCodeHttpResult? _status204NoContent; + private static StatusCodeHttpResult? _status205ResetContent; + private static StatusCodeHttpResult? _status206PartialContent; + private static StatusCodeHttpResult? _status207MultiStatus; + private static StatusCodeHttpResult? _status208AlreadyReported; + private static StatusCodeHttpResult? _status226IMUsed; + private static StatusCodeHttpResult? _status300MultipleChoices; + private static StatusCodeHttpResult? _status301MovedPermanently; + private static StatusCodeHttpResult? _status302Found; + private static StatusCodeHttpResult? _status303SeeOther; + private static StatusCodeHttpResult? _status304NotModified; + private static StatusCodeHttpResult? _status305UseProxy; + private static StatusCodeHttpResult? _status306SwitchProxy; + private static StatusCodeHttpResult? _status307TemporaryRedirect; + private static StatusCodeHttpResult? _status308PermanentRedirect; + private static StatusCodeHttpResult? _status400BadRequest; + private static StatusCodeHttpResult? _status401Unauthorized; + private static StatusCodeHttpResult? _status402PaymentRequired; + private static StatusCodeHttpResult? _status403Forbidden; + private static StatusCodeHttpResult? _status404NotFound; + private static StatusCodeHttpResult? _status405MethodNotAllowed; + private static StatusCodeHttpResult? _status406NotAcceptable; + private static StatusCodeHttpResult? _status407ProxyAuthenticationRequired; + private static StatusCodeHttpResult? _status408RequestTimeout; + private static StatusCodeHttpResult? _status409Conflict; + private static StatusCodeHttpResult? _status410Gone; + private static StatusCodeHttpResult? _status411LengthRequired; + private static StatusCodeHttpResult? _status412PreconditionFailed; + private static StatusCodeHttpResult? _status413RequestEntityTooLarge; + private static StatusCodeHttpResult? _status414RequestUriTooLong; + private static StatusCodeHttpResult? _status415UnsupportedMediaType; + private static StatusCodeHttpResult? _status416RequestedRangeNotSatisfiable; + private static StatusCodeHttpResult? _status417ExpectationFailed; + private static StatusCodeHttpResult? _status418ImATeapot; + private static StatusCodeHttpResult? _status419AuthenticationTimeout; + private static StatusCodeHttpResult? _status421MisdirectedRequest; + private static StatusCodeHttpResult? _status422UnprocessableEntity; + private static StatusCodeHttpResult? _status423Locked; + private static StatusCodeHttpResult? _status424FailedDependency; + private static StatusCodeHttpResult? _status426UpgradeRequired; + private static StatusCodeHttpResult? _status428PreconditionRequired; + private static StatusCodeHttpResult? _status429TooManyRequests; + private static StatusCodeHttpResult? _status431RequestHeaderFieldsTooLarge; + private static StatusCodeHttpResult? _status451UnavailableForLegalReasons; + private static StatusCodeHttpResult? _status500InternalServerError; + private static StatusCodeHttpResult? _status501NotImplemented; + private static StatusCodeHttpResult? _status502BadGateway; + private static StatusCodeHttpResult? _status503ServiceUnavailable; + private static StatusCodeHttpResult? _status504GatewayTimeout; + private static StatusCodeHttpResult? _status505HttpVersionNotsupported; + private static StatusCodeHttpResult? _status506VariantAlsoNegotiates; + private static StatusCodeHttpResult? _status507InsufficientStorage; + private static StatusCodeHttpResult? _status508LoopDetected; + private static StatusCodeHttpResult? _status510NotExtended; + private static StatusCodeHttpResult? _status511NetworkAuthenticationRequired; - internal static Status StatusCode(int statusCode) + internal static StatusCodeHttpResult StatusCode(int statusCode) { if (statusCode is (< 100) or (> 599)) { // No HTTP status code assigned outside the 100..599 range // so, it will not be available in the cache - return new Status(statusCode); + return new StatusCodeHttpResult(statusCode); } return statusCode switch @@ -146,7 +146,7 @@ internal static Status StatusCode(int statusCode) StatusCodes.Status508LoopDetected => _status508LoopDetected ??= new(StatusCodes.Status508LoopDetected), StatusCodes.Status510NotExtended => _status510NotExtended ??= new(StatusCodes.Status510NotExtended), StatusCodes.Status511NetworkAuthenticationRequired => _status511NetworkAuthenticationRequired ??= new(StatusCodes.Status511NetworkAuthenticationRequired), - _ => new Status(statusCode), + _ => new StatusCodeHttpResult(statusCode), }; } } diff --git a/src/Http/Http.Results/src/ResultsCache.StatusCodes.tt b/src/Http/Http.Results/src/ResultsCache.StatusCodes.tt index 3b593cf822d4..0c4450019f45 100644 --- a/src/Http/Http.Results/src/ResultsCache.StatusCodes.tt +++ b/src/Http/Http.Results/src/ResultsCache.StatusCodes.tt @@ -84,16 +84,16 @@ namespace Microsoft.AspNetCore.Http; internal partial class ResultsCache { <# foreach (var statusCode in statusCodes) { #> - private static Status? _status<#= statusCode.Name #>; + private static StatusCodeHttpResult? _status<#= statusCode.Name #>; <# } #> - internal static Status StatusCode(int statusCode) + internal static StatusCodeHttpResult StatusCode(int statusCode) { if (statusCode is (< 100) or (> 599)) { // No HTTP status code assigned outside the 100..599 range // so, it will not be available in the cache - return new Status(statusCode); + return new StatusCodeHttpResult(statusCode); } return statusCode switch @@ -101,7 +101,7 @@ internal partial class ResultsCache <# foreach (var statusCode in statusCodes) { #> StatusCodes.Status<#= statusCode.Name #> => _status<#= statusCode.Name #> ??= new(StatusCodes.Status<#= statusCode.Name #>), <# } #> - _ => new Status(statusCode), + _ => new StatusCodeHttpResult(statusCode), }; } } diff --git a/src/Http/Http.Results/src/ResultsCache.cs b/src/Http/Http.Results/src/ResultsCache.cs index 2caee1aff91b..aed0796bfc55 100644 --- a/src/Http/Http.Results/src/ResultsCache.cs +++ b/src/Http/Http.Results/src/ResultsCache.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Http; internal static partial class ResultsCache { public static NotFound NotFound { get; } = new(); - public static Unauthorized Unauthorized { get; } = new(); + public static UnauthorizedHttpResult Unauthorized { get; } = new(); public static BadRequest BadRequest { get; } = new(); public static Conflict Conflict { get; } = new(); public static NoContent NoContent { get; } = new(); diff --git a/src/Http/Http.Results/src/ResultsOfT.cs b/src/Http/Http.Results/src/ResultsOfT.cs index d868e99b44b3..33559b6c6e98 100644 --- a/src/Http/Http.Results/src/ResultsOfT.cs +++ b/src/Http/Http.Results/src/ResultsOfT.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Http.Metadata; -namespace Microsoft.AspNetCore.Http; +namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that could be one of two different types. On execution will diff --git a/src/Http/Http.Results/src/SignIn.cs b/src/Http/Http.Results/src/SignInHttpResult.cs similarity index 87% rename from src/Http/Http.Results/src/SignIn.cs rename to src/Http/Http.Results/src/SignInHttpResult.cs index 678c9cc85968..8ce3b7276732 100644 --- a/src/Http/Http.Results/src/SignIn.cs +++ b/src/Http/Http.Results/src/SignInHttpResult.cs @@ -11,26 +11,26 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that on execution invokes . /// -public sealed partial class SignIn : IResult +public sealed partial class SignInHttpResult : IResult { /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// default authentication scheme. /// /// The claims principal containing the user claims. - internal SignIn(ClaimsPrincipal principal) + internal SignInHttpResult(ClaimsPrincipal principal) : this(principal, authenticationScheme: null, properties: null) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme and . /// /// The claims principal containing the user claims. /// The authentication schemes to use when signing in the user. /// used to perform the sign-in operation. - internal SignIn(ClaimsPrincipal principal, string? authenticationScheme, AuthenticationProperties? properties) + internal SignInHttpResult(ClaimsPrincipal principal, string? authenticationScheme, AuthenticationProperties? properties) { Principal = principal ?? throw new ArgumentNullException(nameof(principal)); AuthenticationScheme = authenticationScheme; diff --git a/src/Http/Http.Results/src/SignOut.cs b/src/Http/Http.Results/src/SignOutHttpResult.cs similarity index 80% rename from src/Http/Http.Results/src/SignOut.cs rename to src/Http/Http.Results/src/SignOutHttpResult.cs index e3c53f645f3b..515fb89e4183 100644 --- a/src/Http/Http.Results/src/SignOut.cs +++ b/src/Http/Http.Results/src/SignOutHttpResult.cs @@ -11,64 +11,64 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// /// An that on execution invokes . /// -public sealed partial class SignOut : IResult +public sealed partial class SignOutHttpResult : IResult { /// - /// Initializes a new instance of with the default sign out scheme. + /// Initializes a new instance of with the default sign out scheme. /// - internal SignOut() + internal SignOutHttpResult() : this(Array.Empty()) { } /// - /// Initializes a new instance of with the default sign out scheme. + /// Initializes a new instance of with the default sign out scheme. /// specified authentication scheme and . /// /// used to perform the sign-out operation. - internal SignOut(AuthenticationProperties properties) + internal SignOutHttpResult(AuthenticationProperties properties) : this(Array.Empty(), properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme. /// /// The authentication scheme to use when signing out the user. - internal SignOut(string authenticationScheme) + internal SignOutHttpResult(string authenticationScheme) : this(new[] { authenticationScheme }) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes. /// /// The authentication schemes to use when signing out the user. - internal SignOut(IList authenticationSchemes) + internal SignOutHttpResult(IList authenticationSchemes) : this(authenticationSchemes, properties: null) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication scheme and . /// /// The authentication schemes to use when signing out the user. /// used to perform the sign-out operation. - internal SignOut(string authenticationScheme, AuthenticationProperties? properties) + internal SignOutHttpResult(string authenticationScheme, AuthenticationProperties? properties) : this(new[] { authenticationScheme }, properties) { } /// - /// Initializes a new instance of with the + /// Initializes a new instance of with the /// specified authentication schemes and . /// /// The authentication scheme to use when signing out the user. /// used to perform the sign-out operation. - internal SignOut(IList authenticationSchemes, AuthenticationProperties? properties) + internal SignOutHttpResult(IList authenticationSchemes, AuthenticationProperties? properties) { if (authenticationSchemes is null) { diff --git a/src/Http/Http.Results/src/Status.cs b/src/Http/Http.Results/src/StatusCodeHttpResult.cs similarity index 89% rename from src/Http/Http.Results/src/Status.cs rename to src/Http/Http.Results/src/StatusCodeHttpResult.cs index e83d618a6a4a..ad951df8beb7 100644 --- a/src/Http/Http.Results/src/Status.cs +++ b/src/Http/Http.Results/src/StatusCodeHttpResult.cs @@ -10,14 +10,14 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// Represents an that when executed will /// produce an HTTP response with the given response status code. /// -public sealed partial class Status : IResult +public sealed partial class StatusCodeHttpResult : IResult { /// - /// Initializes a new instance of the class + /// Initializes a new instance of the class /// with the given . /// /// The HTTP status code of the response. - internal Status(int statusCode) + internal StatusCodeHttpResult(int statusCode) { StatusCode = statusCode; } diff --git a/src/Http/Http.Results/src/TypedResults.cs b/src/Http/Http.Results/src/TypedResults.cs index ded0af9549d4..06912c0a2a4e 100644 --- a/src/Http/Http.Results/src/TypedResults.cs +++ b/src/Http/Http.Results/src/TypedResults.cs @@ -14,854 +14,856 @@ namespace Microsoft.AspNetCore.Http; /// -/// A factory for . +/// A typed factory for types in . /// -public static partial class Results +public static class TypedResults { /// - /// A typed factory for . + /// Creates an that on execution invokes . + /// + /// The behavior of this method depends on the in use. + /// and + /// are among likely status results. + /// /// - public static class Typed + /// used to perform the authentication + /// challenge. + /// The authentication schemes to challenge. + /// The created for the response. + public static ChallengeHttpResult Challenge( + AuthenticationProperties? properties = null, + IList? authenticationSchemes = null) + => new(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + + /// + /// Creates a that on execution invokes . + /// + /// By default, executing this result returns a . Some authentication schemes, such as cookies, + /// will convert to a redirect to show a login page. + /// + /// + /// used to perform the authentication + /// challenge. + /// The authentication schemes to challenge. + /// The created for the response. + /// + /// Some authentication schemes, such as cookies, will convert to + /// a redirect to show a login page. + /// + public static ForbidHttpResult Forbid(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) + => new(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + + /// + /// Creates an that on execution invokes . + /// + /// The containing the user claims. + /// used to perform the sign-in operation. + /// The authentication scheme to use for the sign-in operation. + /// The created for the response. + public static SignInHttpResult SignIn( + ClaimsPrincipal principal, + AuthenticationProperties? properties = null, + string? authenticationScheme = null) + => new(principal, authenticationScheme, properties); + + /// + /// Creates an that on execution invokes . + /// + /// used to perform the sign-out operation. + /// The authentication scheme to use for the sign-out operation. + /// The created for the response. + public static SignOutHttpResult SignOut(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) + => new(authenticationSchemes ?? Array.Empty(), properties); + + /// + /// Writes the string to the HTTP response. + /// + /// This is an alias for . + /// + /// + /// The content to write to the response. + /// The content type (MIME type). + /// The content encoding. + /// The created object for the response. + /// + /// If encoding is provided by both the 'charset' and the parameters, then + /// the parameter is chosen as the final encoding. + /// + public static ContentHttpResult Content(string content, string? contentType = null, Encoding? contentEncoding = null) + => Text(content, contentType, contentEncoding); + + /// + /// Writes the string to the HTTP response. + /// + /// This is an alias for . + /// + /// + /// The content to write to the response. + /// The content type (MIME type). + /// The content encoding. + /// The created object for the response. + /// + /// If encoding is provided by both the 'charset' and the parameters, then + /// the parameter is chosen as the final encoding. + /// + public static ContentHttpResult Text(string content, string? contentType = null, Encoding? contentEncoding = null) { - /// - /// Creates an that on execution invokes . - /// - /// The behavior of this method depends on the in use. - /// and - /// are among likely status results. - /// - /// - /// used to perform the authentication - /// challenge. - /// The authentication schemes to challenge. - /// The created for the response. - public static Challenge Challenge( - AuthenticationProperties? properties = null, - IList? authenticationSchemes = null) - => new(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); - - /// - /// Creates a that on execution invokes . - /// - /// By default, executing this result returns a . Some authentication schemes, such as cookies, - /// will convert to a redirect to show a login page. - /// - /// - /// used to perform the authentication - /// challenge. - /// The authentication schemes to challenge. - /// The created for the response. - /// - /// Some authentication schemes, such as cookies, will convert to - /// a redirect to show a login page. - /// - public static Forbid Forbid(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); - - /// - /// Creates an that on execution invokes . - /// - /// The containing the user claims. - /// used to perform the sign-in operation. - /// The authentication scheme to use for the sign-in operation. - /// The created for the response. - public static SignIn SignIn( - ClaimsPrincipal principal, - AuthenticationProperties? properties = null, - string? authenticationScheme = null) - => new(principal, authenticationScheme, properties); - - /// - /// Creates an that on execution invokes . - /// - /// used to perform the sign-out operation. - /// The authentication scheme to use for the sign-out operation. - /// The created for the response. - public static SignOut SignOut(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new(authenticationSchemes ?? Array.Empty(), properties); - - /// - /// Writes the string to the HTTP response. - /// - /// This is an alias for . - /// - /// - /// The content to write to the response. - /// The content type (MIME type). - /// The content encoding. - /// The created object for the response. - /// - /// If encoding is provided by both the 'charset' and the parameters, then - /// the parameter is chosen as the final encoding. - /// - public static Content Content(string content, string? contentType = null, Encoding? contentEncoding = null) - => Text(content, contentType, contentEncoding); - - /// - /// Writes the string to the HTTP response. - /// - /// This is an alias for . - /// - /// - /// The content to write to the response. - /// The content type (MIME type). - /// The content encoding. - /// The created object for the response. - /// - /// If encoding is provided by both the 'charset' and the parameters, then - /// the parameter is chosen as the final encoding. - /// - public static Content Text(string content, string? contentType = null, Encoding? contentEncoding = null) + MediaTypeHeaderValue? mediaTypeHeaderValue = null; + if (contentType is not null) { - MediaTypeHeaderValue? mediaTypeHeaderValue = null; - if (contentType is not null) - { - mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType); - mediaTypeHeaderValue.Encoding = contentEncoding ?? mediaTypeHeaderValue.Encoding; - } - - return new(content, mediaTypeHeaderValue?.ToString()); + mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType); + mediaTypeHeaderValue.Encoding = contentEncoding ?? mediaTypeHeaderValue.Encoding; } - /// - /// Writes the string to the HTTP response. - /// - /// The content to write to the response. - /// The content type (MIME type). - /// The created object for the response. - public static Content Content(string content, MediaTypeHeaderValue contentType) - => new(content, contentType.ToString()); - - /// - /// Creates a that serializes the specified object to JSON. - /// - /// The object to write as JSON. - /// The serializer options to use when serializing the value. - /// The content-type to set on the response. - /// The status code to set on the response. - /// The created that serializes the specified - /// as JSON format for the response. - /// Callers should cache an instance of serializer settings to avoid - /// recreating cached data with each call. - public static Json Json(TValue? data, JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) - => new(data, statusCode, options) - { - ContentType = contentType, - }; - - /// - /// Writes the byte-array content to the response. - /// - /// This supports range requests ( or - /// if the range is not satisfiable). - /// - /// - /// This API is an alias for . - /// - /// The file contents. - /// The Content-Type of the file. - /// The suggested file name. - /// Set to true to enable range requests processing. - /// The of when the file was last modified. - /// The associated with the file. - /// The created for the response. + return new(content, mediaTypeHeaderValue?.ToString()); + } + + /// + /// Writes the string to the HTTP response. + /// + /// The content to write to the response. + /// The content type (MIME type). + /// The created object for the response. + public static ContentHttpResult Content(string content, MediaTypeHeaderValue contentType) + => new(content, contentType.ToString()); + + /// + /// Creates a that serializes the specified object to JSON. + /// + /// The type of object that will be JSON serialized to the response body. + /// The object to write as JSON. + /// The serializer options to use when serializing the value. + /// The content-type to set on the response. + /// The status code to set on the response. + /// The created that serializes the specified + /// as JSON format for the response. + /// Callers should cache an instance of serializer settings to avoid + /// recreating cached data with each call. + public static JsonHttpResult Json(TValue? data, JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) + => new(data, statusCode, options) + { + ContentType = contentType, + }; + + /// + /// Writes the byte-array content to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// This API is an alias for . + /// + /// The file contents. + /// The Content-Type of the file. + /// The suggested file name. + /// Set to true to enable range requests processing. + /// The of when the file was last modified. + /// The associated with the file. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static FileContent File( + public static FileContentHttpResult File( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - byte[] fileContents, - string? contentType = null, - string? fileDownloadName = null, - bool enableRangeProcessing = false, - DateTimeOffset? lastModified = null, - EntityTagHeaderValue? entityTag = null) - => new(fileContents, contentType) - { - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - LastModified = lastModified, - EntityTag = entityTag, - }; - - /// - /// Writes the byte-array content to the response. - /// - /// This supports range requests ( or - /// if the range is not satisfiable). - /// - /// - /// This API is an alias for . - /// - /// The file contents. - /// The Content-Type of the file. - /// The suggested file name. - /// Set to true to enable range requests processing. - /// The of when the file was last modified. - /// The associated with the file. - /// The created for the response. + byte[] fileContents, + string? contentType = null, + string? fileDownloadName = null, + bool enableRangeProcessing = false, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null) + => new(fileContents, contentType) + { + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + LastModified = lastModified, + EntityTag = entityTag, + }; + + /// + /// Writes the byte-array content to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// This API is an alias for . + /// + /// The file contents. + /// The Content-Type of the file. + /// The suggested file name. + /// Set to true to enable range requests processing. + /// The of when the file was last modified. + /// The associated with the file. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static FileContent Bytes( + public static FileContentHttpResult Bytes( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - byte[] contents, - string? contentType = null, - string? fileDownloadName = null, - bool enableRangeProcessing = false, - DateTimeOffset? lastModified = null, - EntityTagHeaderValue? entityTag = null) - => new(contents, contentType) - { - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - LastModified = lastModified, - EntityTag = entityTag, - }; - - /// - /// Writes the byte-array content to the response. - /// - /// This supports range requests ( or - /// if the range is not satisfiable). - /// - /// - /// The file contents. - /// The Content-Type of the file. - /// The suggested file name. - /// Set to true to enable range requests processing. - /// The of when the file was last modified. - /// The associated with the file. - /// The created for the response. + byte[] contents, + string? contentType = null, + string? fileDownloadName = null, + bool enableRangeProcessing = false, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null) + => new(contents, contentType) + { + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + LastModified = lastModified, + EntityTag = entityTag, + }; + + /// + /// Writes the byte-array content to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The file contents. + /// The Content-Type of the file. + /// The suggested file name. + /// Set to true to enable range requests processing. + /// The of when the file was last modified. + /// The associated with the file. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static FileContent Bytes( + public static FileContentHttpResult Bytes( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - ReadOnlyMemory contents, - string? contentType = null, - string? fileDownloadName = null, - bool enableRangeProcessing = false, - DateTimeOffset? lastModified = null, - EntityTagHeaderValue? entityTag = null) - => new(contents, contentType) - { - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - LastModified = lastModified, - EntityTag = entityTag, - }; - - /// - /// Writes the specified to the response. - /// - /// This supports range requests ( or - /// if the range is not satisfiable). - /// - /// - /// This API is an alias for . - /// - /// - /// The with the contents of the file. - /// The Content-Type of the file. - /// The the file name to be used in the Content-Disposition header. - /// The of when the file was last modified. - /// Used to configure the Last-Modified response header and perform conditional range requests. - /// The to be configure the ETag response header - /// and perform conditional requests. - /// Set to true to enable range requests processing. - /// The created for the response. - /// - /// The parameter is disposed after the response is sent. - /// + ReadOnlyMemory contents, + string? contentType = null, + string? fileDownloadName = null, + bool enableRangeProcessing = false, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null) + => new(contents, contentType) + { + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + LastModified = lastModified, + EntityTag = entityTag, + }; + + /// + /// Writes the specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// This API is an alias for . + /// + /// + /// The with the contents of the file. + /// The Content-Type of the file. + /// The the file name to be used in the Content-Disposition header. + /// The of when the file was last modified. + /// Used to configure the Last-Modified response header and perform conditional range requests. + /// The to be configure the ETag response header + /// and perform conditional requests. + /// Set to true to enable range requests processing. + /// The created for the response. + /// + /// The parameter is disposed after the response is sent. + /// #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static HttpFileStream File( + public static FileStreamHttpResult File( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - Stream fileStream, - string? contentType = null, - string? fileDownloadName = null, - DateTimeOffset? lastModified = null, - EntityTagHeaderValue? entityTag = null, - bool enableRangeProcessing = false) + Stream fileStream, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(fileStream, contentType) { - return new(fileStream, contentType) - { - LastModified = lastModified, - EntityTag = entityTag, - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - }; - } + LastModified = lastModified, + EntityTag = entityTag, + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + }; + } - /// - /// Writes the specified to the response. - /// - /// This supports range requests ( or - /// if the range is not satisfiable). - /// - /// - /// This API is an alias for . - /// - /// - /// The to write to the response. - /// The Content-Type of the response. Defaults to application/octet-stream. - /// The the file name to be used in the Content-Disposition header. - /// The of when the file was last modified. - /// Used to configure the Last-Modified response header and perform conditional range requests. - /// The to be configure the ETag response header - /// and perform conditional requests. - /// Set to true to enable range requests processing. - /// The created for the response. - /// - /// The parameter is disposed after the response is sent. - /// + /// + /// Writes the specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// This API is an alias for . + /// + /// + /// The to write to the response. + /// The Content-Type of the response. Defaults to application/octet-stream. + /// The the file name to be used in the Content-Disposition header. + /// The of when the file was last modified. + /// Used to configure the Last-Modified response header and perform conditional range requests. + /// The to be configure the ETag response header + /// and perform conditional requests. + /// Set to true to enable range requests processing. + /// The created for the response. + /// + /// The parameter is disposed after the response is sent. + /// #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static HttpFileStream Stream( + public static FileStreamHttpResult Stream( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - Stream stream, - string? contentType = null, - string? fileDownloadName = null, - DateTimeOffset? lastModified = null, - EntityTagHeaderValue? entityTag = null, - bool enableRangeProcessing = false) + Stream stream, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(stream, contentType) { - return new(stream, contentType) - { - LastModified = lastModified, - EntityTag = entityTag, - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - }; - } + LastModified = lastModified, + EntityTag = entityTag, + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + }; + } - /// - /// Writes the contents of specified to the response. - /// - /// This supports range requests ( or - /// if the range is not satisfiable). - /// - /// - /// The to write to the response. - /// The Content-Type of the response. Defaults to application/octet-stream. - /// The the file name to be used in the Content-Disposition header. - /// The of when the file was last modified. - /// Used to configure the Last-Modified response header and perform conditional range requests. - /// The to be configure the ETag response header - /// and perform conditional requests. - /// Set to true to enable range requests processing. - /// The created for the response. - /// - /// The parameter is completed after the response is sent. - /// + /// + /// Writes the contents of specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The to write to the response. + /// The Content-Type of the response. Defaults to application/octet-stream. + /// The the file name to be used in the Content-Disposition header. + /// The of when the file was last modified. + /// Used to configure the Last-Modified response header and perform conditional range requests. + /// The to be configure the ETag response header + /// and perform conditional requests. + /// Set to true to enable range requests processing. + /// The created for the response. + /// + /// The parameter is completed after the response is sent. + /// #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static HttpFileStream Stream( + public static FileStreamHttpResult Stream( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - PipeReader pipeReader, - string? contentType = null, - string? fileDownloadName = null, - DateTimeOffset? lastModified = null, - EntityTagHeaderValue? entityTag = null, - bool enableRangeProcessing = false) + PipeReader pipeReader, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(pipeReader.AsStream(), contentType) { - return new(pipeReader.AsStream(), contentType) - { - LastModified = lastModified, - EntityTag = entityTag, - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - }; - } + LastModified = lastModified, + EntityTag = entityTag, + FileDownloadName = fileDownloadName, + EnableRangeProcessing = enableRangeProcessing, + }; + } - /// - /// Allows writing directly to the response body. - /// - /// This supports range requests ( or - /// if the range is not satisfiable). - /// - /// - /// The callback that allows users to write directly to the response body. - /// The Content-Type of the response. Defaults to application/octet-stream. - /// The the file name to be used in the Content-Disposition header. - /// The of when the file was last modified. - /// Used to configure the Last-Modified response header and perform conditional range requests. - /// The to be configure the ETag response header - /// and perform conditional requests. - /// The created for the response. + /// + /// Allows writing directly to the response body. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The callback that allows users to write directly to the response body. + /// The Content-Type of the response. Defaults to application/octet-stream. + /// The the file name to be used in the Content-Disposition header. + /// The of when the file was last modified. + /// Used to configure the Last-Modified response header and perform conditional range requests. + /// The to be configure the ETag response header + /// and perform conditional requests. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static PushStream Stream( + public static PushStreamHttpResult Stream( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - Func streamWriterCallback, - string? contentType = null, - string? fileDownloadName = null, - DateTimeOffset? lastModified = null, - EntityTagHeaderValue? entityTag = null) + Func streamWriterCallback, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null) + { + return new(streamWriterCallback, contentType) { - return new(streamWriterCallback, contentType) - { - LastModified = lastModified, - EntityTag = entityTag, - FileDownloadName = fileDownloadName, - }; - } + LastModified = lastModified, + EntityTag = entityTag, + FileDownloadName = fileDownloadName, + }; + } - /// - /// Writes the file at the specified to the response. - /// - /// This supports range requests ( or - /// if the range is not satisfiable). - /// - /// - /// The path to the file. When not rooted, resolves the path relative to . - /// The Content-Type of the file. - /// The suggested file name. - /// The of when the file was last modified. - /// The associated with the file. - /// Set to true to enable range requests processing. - /// The created for the response. + /// + /// Writes the file at the specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The path to the file. When not rooted, resolves the path relative to . + /// The Content-Type of the file. + /// The suggested file name. + /// The of when the file was last modified. + /// The associated with the file. + /// Set to true to enable range requests processing. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static PhysicalFile PhysicalFile( + public static PhysicalFileHttpResult PhysicalFile( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - string path, - string? contentType = null, - string? fileDownloadName = null, - DateTimeOffset? lastModified = null, - EntityTagHeaderValue? entityTag = null, - bool enableRangeProcessing = false) + string path, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(path, contentType) { - return new(path, contentType) - { - FileDownloadName = fileDownloadName, - LastModified = lastModified, - EntityTag = entityTag, - EnableRangeProcessing = enableRangeProcessing, - }; - } + FileDownloadName = fileDownloadName, + LastModified = lastModified, + EntityTag = entityTag, + EnableRangeProcessing = enableRangeProcessing, + }; + } - /// - /// Writes the file at the specified to the response. - /// - /// This supports range requests ( or - /// if the range is not satisfiable). - /// - /// - /// The path to the file. When not rooted, resolves the path relative to . - /// The Content-Type of the file. - /// The suggested file name. - /// The of when the file was last modified. - /// The associated with the file. - /// Set to true to enable range requests processing. - /// The created for the response. + /// + /// Writes the file at the specified to the response. + /// + /// This supports range requests ( or + /// if the range is not satisfiable). + /// + /// + /// The path to the file. When not rooted, resolves the path relative to . + /// The Content-Type of the file. + /// The suggested file name. + /// The of when the file was last modified. + /// The associated with the file. + /// Set to true to enable range requests processing. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static VirtualFile VirtualFile( + public static VirtualFileHttpResult VirtualFile( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - string path, - string? contentType = null, - string? fileDownloadName = null, - DateTimeOffset? lastModified = null, - EntityTagHeaderValue? entityTag = null, - bool enableRangeProcessing = false) + string path, + string? contentType = null, + string? fileDownloadName = null, + DateTimeOffset? lastModified = null, + EntityTagHeaderValue? entityTag = null, + bool enableRangeProcessing = false) + { + return new(path, contentType) { - return new(path, contentType) - { - FileDownloadName = fileDownloadName, - LastModified = lastModified, - EntityTag = entityTag, - EnableRangeProcessing = enableRangeProcessing, - }; - } + FileDownloadName = fileDownloadName, + LastModified = lastModified, + EntityTag = entityTag, + EnableRangeProcessing = enableRangeProcessing, + }; + } - /// - /// Redirects to the specified . - /// - /// When and are set, sets the status code. - /// When is set, sets the status code. - /// When is set, sets the status code. - /// Otherwise, configures . - /// - /// - /// The URL to redirect to. - /// Specifies whether the redirect should be permanent (301) or temporary (302). - /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. - /// The created for the response. - public static Redirect Redirect(string url, bool permanent = false, bool preserveMethod = false) - => new(url, permanent, preserveMethod); - - /// - /// Redirects to the specified . - /// - /// When and are set, sets the status code. - /// When is set, sets the status code. - /// When is set, sets the status code. - /// Otherwise, configures . - /// - /// - /// The local URL to redirect to. - /// Specifies whether the redirect should be permanent (301) or temporary (302). - /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. - /// The created for the response. - public static Redirect LocalRedirect(string localUrl, bool permanent = false, bool preserveMethod = false) - => new(localUrl, acceptLocalUrlOnly: true, permanent, preserveMethod); - - /// - /// Redirects to the specified route. - /// - /// When and are set, sets the status code. - /// When is set, sets the status code. - /// When is set, sets the status code. - /// Otherwise, configures . - /// - /// - /// The name of the route. - /// The parameters for a route. - /// Specifies whether the redirect should be permanent (301) or temporary (302). - /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. - /// The fragment to add to the URL. - /// The created for the response. - public static RedirectToRoute RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) - => new( - routeName: routeName, - routeValues: routeValues, - permanent: permanent, - preserveMethod: preserveMethod, - fragment: fragment); - - /// - /// Creates a object by specifying a . - /// - /// The status code to set on the response. - /// The created object for the response. - public static Status StatusCode(int statusCode) - => ResultsCache.StatusCode(statusCode); - - /// - /// Produces a response. - /// - /// The created for the response. - public static NotFound NotFound() => ResultsCache.NotFound; - - /// - /// Produces a response. - /// - /// The value to be included in the HTTP response body. - /// The created for the response. - public static NotFound NotFound(TValue? value) => new(value); - - /// - /// Produces a response. - /// - /// The created for the response. - public static Unauthorized Unauthorized() => ResultsCache.Unauthorized; - - /// - /// Produces a response. - /// - /// The created for the response. - public static BadRequest BadRequest() => ResultsCache.BadRequest; - - /// - /// Produces a response. - /// - /// The value to be included in the HTTP response body. - /// The created for the response. - public static BadRequest BadRequest(TValue? error) => new(error); - - /// - /// Produces a response. - /// - /// The created for the response. - public static Conflict Conflict() => ResultsCache.Conflict; - - /// - /// Produces a response. - /// - /// The value to be included in the HTTP response body. - /// The created for the response. - public static Conflict Conflict(TValue? error) => new(error); - - /// - /// Produces a response. - /// - /// The created for the response. - public static NoContent NoContent() => ResultsCache.NoContent; - - /// - /// Produces a response. - /// - /// The created for the response. - public static Ok Ok() => ResultsCache.Ok; - - /// - /// Produces a response. - /// - /// The value to be included in the HTTP response body. - /// The created for the response. - public static Ok Ok(TValue? value) => new(value); - - /// - /// Produces a response. - /// - /// The created for the response. - public static UnprocessableEntity UnprocessableEntity() => ResultsCache.UnprocessableEntity; - - /// - /// Produces a response. - /// - /// The value to be included in the HTTP response body. - /// The created for the response. - public static UnprocessableEntity UnprocessableEntity(TValue? error) => new(error); - - /// - /// Produces a response. - /// - /// The value for . - /// The value for . - /// The value for . - /// The value for . - /// The value for . - /// The value for . - /// The created for the response. - public static Problem Problem( - string? detail = null, - string? instance = null, - int? statusCode = null, - string? title = null, - string? type = null, - IDictionary? extensions = null) - { - var problemDetails = new ProblemDetails - { - Detail = detail, - Instance = instance, - Status = statusCode, - Title = title, - Type = type, - }; - - if (extensions is not null) - { - foreach (var extension in extensions) - { - problemDetails.Extensions.Add(extension); - } - } + /// + /// Redirects to the specified . + /// + /// When and are set, sets the status code. + /// When is set, sets the status code. + /// When is set, sets the status code. + /// Otherwise, configures . + /// + /// + /// The URL to redirect to. + /// Specifies whether the redirect should be permanent (301) or temporary (302). + /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. + /// The created for the response. + public static RedirectHttpResult Redirect(string url, bool permanent = false, bool preserveMethod = false) + => new(url, permanent, preserveMethod); - return new(problemDetails); - } + /// + /// Redirects to the specified . + /// + /// When and are set, sets the status code. + /// When is set, sets the status code. + /// When is set, sets the status code. + /// Otherwise, configures . + /// + /// + /// The local URL to redirect to. + /// Specifies whether the redirect should be permanent (301) or temporary (302). + /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. + /// The created for the response. + public static RedirectHttpResult LocalRedirect(string localUrl, bool permanent = false, bool preserveMethod = false) + => new(localUrl, acceptLocalUrlOnly: true, permanent, preserveMethod); - /// - /// Produces a response. - /// - /// The object to produce a response from. - /// The created for the response. - public static Problem Problem(ProblemDetails problemDetails) - { - return new(problemDetails); - } + /// + /// Redirects to the specified route. + /// + /// When and are set, sets the status code. + /// When is set, sets the status code. + /// When is set, sets the status code. + /// Otherwise, configures . + /// + /// + /// The name of the route. + /// The parameters for a route. + /// Specifies whether the redirect should be permanent (301) or temporary (302). + /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. + /// The fragment to add to the URL. + /// The created for the response. + public static RedirectToRouteHttpResult RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) + => new( + routeName: routeName, + routeValues: routeValues, + permanent: permanent, + preserveMethod: preserveMethod, + fragment: fragment); - /// - /// Produces a response - /// with a value. - /// - /// One or more validation errors. - /// The value for . - /// The value for . - /// The status code. - /// The value for . Defaults to "One or more validation errors occurred." - /// The value for . - /// The value for . - /// The created for the response. - public static Problem ValidationProblem( - IDictionary errors, - string? detail = null, - string? instance = null, - int? statusCode = null, - string? title = null, - string? type = null, - IDictionary? extensions = null) - { - var problemDetails = new HttpValidationProblemDetails(errors) - { - Detail = detail, - Instance = instance, - Type = type, - Status = statusCode, - }; + /// + /// Creates a object by specifying a . + /// + /// The status code to set on the response. + /// The created object for the response. + public static StatusCodeHttpResult StatusCode(int statusCode) + => ResultsCache.StatusCode(statusCode); - problemDetails.Title = title ?? problemDetails.Title; + /// + /// Produces a response. + /// + /// The created for the response. + public static NotFound NotFound() => ResultsCache.NotFound; - if (extensions is not null) - { - foreach (var extension in extensions) - { - problemDetails.Extensions.Add(extension); - } - } + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static NotFound NotFound(TValue? value) => new(value); - return new(problemDetails); - } + /// + /// Produces a response. + /// + /// The created for the response. + public static UnauthorizedHttpResult Unauthorized() => ResultsCache.Unauthorized; + + /// + /// Produces a response. + /// + /// The created for the response. + public static BadRequest BadRequest() => ResultsCache.BadRequest; - /// - /// Produces a response. - /// - /// The URI at which the content has been created. - /// The created for the response. - public static Created Created(string uri) + /// + /// Produces a response. + /// + /// The type of error object that will be JSON serialized to the response body. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static BadRequest BadRequest(TValue? error) => new(error); + + /// + /// Produces a response. + /// + /// The created for the response. + public static Conflict Conflict() => ResultsCache.Conflict; + + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Conflict Conflict(TValue? error) => new(error); + + /// + /// Produces a response. + /// + /// The created for the response. + public static NoContent NoContent() => ResultsCache.NoContent; + + /// + /// Produces a response. + /// + /// The created for the response. + public static Ok Ok() => ResultsCache.Ok; + + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Ok Ok(TValue? value) => new(value); + + /// + /// Produces a response. + /// + /// The created for the response. + public static UnprocessableEntity UnprocessableEntity() => ResultsCache.UnprocessableEntity; + + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static UnprocessableEntity UnprocessableEntity(TValue? error) => new(error); + + /// + /// Produces a response. + /// + /// The value for . + /// The value for . + /// The value for . + /// The value for . + /// The value for . + /// The value for . + /// The created for the response. + public static ProblemHttpResult Problem( + string? detail = null, + string? instance = null, + int? statusCode = null, + string? title = null, + string? type = null, + IDictionary? extensions = null) + { + var problemDetails = new ProblemDetails + { + Detail = detail, + Instance = instance, + Status = statusCode, + Title = title, + Type = type, + }; + + if (extensions is not null) { - if (uri == null) + foreach (var extension in extensions) { - throw new ArgumentNullException(nameof(uri)); + problemDetails.Extensions.Add(extension); } - - return new(uri); } - /// - /// Produces a response. - /// - /// The URI at which the content has been created. - /// The value to be included in the HTTP response body. - /// The created for the response. - public static Created Created(string uri, TValue? value) + return new(problemDetails); + } + + /// + /// Produces a response. + /// + /// The object to produce a response from. + /// The created for the response. + public static ProblemHttpResult Problem(ProblemDetails problemDetails) + { + return new(problemDetails); + } + + /// + /// Produces a response with an value. + /// + /// One or more validation errors. + /// The value for . + /// The value for . + /// The value for . Defaults to "One or more validation errors occurred." + /// The value for . + /// The value for . + /// The created for the response. + public static ValidationProblem ValidationProblem( + IDictionary errors, + string? detail = null, + string? instance = null, + string? title = null, + string? type = null, + IDictionary? extensions = null) + { + var problemDetails = new HttpValidationProblemDetails(errors) { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } + Detail = detail, + Instance = instance, + Type = type, + }; - return new(uri, value); - } + problemDetails.Title = title ?? problemDetails.Title; - /// - /// Produces a response. - /// - /// The URI at which the content has been created. - /// The created for the response. - public static Created Created(Uri uri) + if (extensions is not null) { - if (uri == null) + foreach (var extension in extensions) { - throw new ArgumentNullException(nameof(uri)); + problemDetails.Extensions.Add(extension); } + } - return new(uri); + return new(problemDetails); + } + + /// + /// Produces a response. + /// + /// The URI at which the content has been created. + /// The created for the response. + public static Created Created(string uri) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); } - /// - /// Produces a response. - /// - /// The URI at which the content has been created. - /// The value to be included in the HTTP response body. - /// The created for the response. - public static Created Created(Uri uri, TValue? value) + return new(uri); + } + + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The URI at which the content has been created. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Created Created(string uri, TValue? value) + { + if (uri == null) { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } + throw new ArgumentNullException(nameof(uri)); + } + + return new(uri, value); + } + + /// + /// Produces a response. + /// + /// The URI at which the content has been created. + /// The created for the response. + public static Created Created(Uri uri) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); + } - return new(uri, value); + return new(uri); + } + + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The URI at which the content has been created. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Created Created(Uri uri, TValue? value) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); } - /// - /// Produces a response. - /// - /// The name of the route to use for generating the URL. - /// The route data to use for generating the URL. - /// The created for the response. + return new(uri, value); + } + + /// + /// Produces a response. + /// + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static CreatedAtRoute CreatedAtRoute(string? routeName = null, object? routeValues = null) + public static CreatedAtRoute CreatedAtRoute(string? routeName = null, object? routeValues = null) #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - => new(routeName, routeValues); - - /// - /// Produces a response. - /// - /// The name of the route to use for generating the URL. - /// The route data to use for generating the URL. - /// The value to be included in the HTTP response body. - /// The created for the response. + => new(routeName, routeValues); + + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + /// The value to be included in the HTTP response body. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static CreatedAtRoute CreatedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) + public static CreatedAtRoute CreatedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - => new(routeName, routeValues, value); - - /// - /// Produces a response. - /// - /// The URI with the location at which the status of requested content can be monitored. - /// The created for the response. - public static Accepted Accepted(string uri) - { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } + => new(routeName, routeValues, value); - return new(uri); + /// + /// Produces a response. + /// + /// The URI with the location at which the status of requested content can be monitored. + /// The created for the response. + public static Accepted Accepted(string uri) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); } - /// - /// Produces a response. - /// - /// The URI with the location at which the status of requested content can be monitored. - /// The value to be included in the HTTP response body. - /// The created for the response. - public static Accepted Accepted(string uri, TValue? value) - { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } + return new(uri); + } - return new(uri, value); + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The URI with the location at which the status of requested content can be monitored. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Accepted Accepted(string uri, TValue? value) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); } - /// - /// Produces a response. - /// - /// The URI with the location at which the status of requested content can be monitored. - /// The created for the response. - public static Accepted Accepted(Uri uri) - { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } + return new(uri, value); + } - return new(uri); + /// + /// Produces a response. + /// + /// The URI with the location at which the status of requested content can be monitored. + /// The created for the response. + public static Accepted Accepted(Uri uri) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); } - /// - /// Produces a response. - /// - /// The URI with the location at which the status of requested content can be monitored. - /// The value to be included in the HTTP response body. - /// The created for the response. - public static Accepted Accepted(Uri uri, TValue? value) - { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } + return new(uri); + } - return new(uri, value); + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The URI with the location at which the status of requested content can be monitored. + /// The value to be included in the HTTP response body. + /// The created for the response. + public static Accepted Accepted(Uri uri, TValue? value) + { + if (uri == null) + { + throw new ArgumentNullException(nameof(uri)); } - /// - /// Produces a response. - /// - /// The name of the route to use for generating the URL. - /// The route data to use for generating the URL. - /// The created for the response. + return new(uri, value); + } + + /// + /// Produces a response. + /// + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static AcceptedAtRoute AcceptedAtRoute(string? routeName = null, object? routeValues = null) + public static AcceptedAtRoute AcceptedAtRoute(string? routeName = null, object? routeValues = null) #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - => new(routeName, routeValues); - - /// - /// Produces a response. - /// - /// The name of the route to use for generating the URL. - /// The route data to use for generating the URL. - /// The value to be included in the HTTP response body. - /// The created for the response. + => new(routeName, routeValues); + + /// + /// Produces a response. + /// + /// The type of object that will be JSON serialized to the response body. + /// The name of the route to use for generating the URL. + /// The route data to use for generating the URL. + /// The value to be included in the HTTP response body. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters - public static AcceptedAtRoute AcceptedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) + public static AcceptedAtRoute AcceptedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - => new(routeName, routeValues, value); - } + => new(routeName, routeValues, value); } diff --git a/src/Http/Http.Results/src/Unauthorized.cs b/src/Http/Http.Results/src/UnauthorizedHttpResult.cs similarity index 76% rename from src/Http/Http.Results/src/Unauthorized.cs rename to src/Http/Http.Results/src/UnauthorizedHttpResult.cs index 305b04db3fab..db04fd1dedfa 100644 --- a/src/Http/Http.Results/src/Unauthorized.cs +++ b/src/Http/Http.Results/src/UnauthorizedHttpResult.cs @@ -1,22 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - -using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// Represents an that when executed will /// produce an HTTP response with the No Unauthorized (401) status code. /// -public sealed class Unauthorized : IResult, IEndpointMetadataProvider +public sealed class UnauthorizedHttpResult : IResult { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - internal Unauthorized() + internal UnauthorizedHttpResult() { } @@ -37,10 +37,4 @@ public Task ExecuteAsync(HttpContext httpContext) return Task.CompletedTask; } - - /// - static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) - { - context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status401Unauthorized)); - } } diff --git a/src/Http/Http.Results/src/UnprocessableEntity.cs b/src/Http/Http.Results/src/UnprocessableEntity.cs index 2917c0c7233a..b9884f406596 100644 --- a/src/Http/Http.Results/src/UnprocessableEntity.cs +++ b/src/Http/Http.Results/src/UnprocessableEntity.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Unprocessable Entity (422) status code. diff --git a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs index ce779f7469b0..f45a1e6be46f 100644 --- a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs +++ b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs @@ -1,16 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.HttpResults; - using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +namespace Microsoft.AspNetCore.Http.HttpResults; + /// /// An that on execution will write an object to the response /// with Unprocessable Entity (422) status code. /// +/// The type of object that will be JSON serialized to the response body. public sealed class UnprocessableEntity : IResult, IEndpointMetadataProvider { /// diff --git a/src/Http/Http.Results/src/ValidationProblem.cs b/src/Http/Http.Results/src/ValidationProblem.cs new file mode 100644 index 000000000000..3aebd3fef166 --- /dev/null +++ b/src/Http/Http.Results/src/ValidationProblem.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Http.Metadata; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +/// +/// An that on execution will write Problem Details +/// HTTP API responses based on https://tools.ietf.org/html/rfc7807 +/// +public sealed class ValidationProblem : IResult, IEndpointMetadataProvider +{ + /// + /// Creates a new instance with + /// the provided . + /// + /// The instance to format in the entity body. + internal ValidationProblem(HttpValidationProblemDetails problemDetails) + { + ProblemDetails = problemDetails; + HttpResultsHelper.ApplyProblemDetailsDefaults(ProblemDetails, statusCode: StatusCodes.Status400BadRequest); + } + + /// + /// Gets the instance. + /// + public HttpValidationProblemDetails ProblemDetails { get; } + + /// + /// Gets the value for the Content-Type header. + /// + public string ContentType => "application/problem+json"; + + /// + /// Gets the HTTP status code. + /// + public int StatusCode => StatusCodes.Status400BadRequest; + + public Task ExecuteAsync(HttpContext httpContext) + { + var loggerFactory = httpContext.RequestServices.GetRequiredService(); + var logger = loggerFactory.CreateLogger(typeof(ValidationProblem)); + + HttpResultsHelper.Log.WritingResultAsStatusCode(logger, StatusCode); + httpContext.Response.StatusCode = StatusCode; + + return HttpResultsHelper.WriteResultAsJsonAsync( + httpContext, + logger, + value: ProblemDetails, + ContentType); + } + + /// + public static void PopulateMetadata(EndpointMetadataContext context) + { + context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(HttpValidationProblemDetails), StatusCodes.Status400BadRequest, "application/problem+json")); + } +} diff --git a/src/Http/Http.Results/src/VirtualFile.cs b/src/Http/Http.Results/src/VirtualFileHttpResult.cs similarity index 92% rename from src/Http/Http.Results/src/VirtualFile.cs rename to src/Http/Http.Results/src/VirtualFileHttpResult.cs index 05ae588f79d9..6739676d9700 100644 --- a/src/Http/Http.Results/src/VirtualFile.cs +++ b/src/Http/Http.Results/src/VirtualFileHttpResult.cs @@ -14,30 +14,30 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// A that on execution writes the file specified /// using a virtual path to the response using mechanisms provided by the host. /// -public sealed class VirtualFile : IResult +public sealed class VirtualFileHttpResult : IResult { private string _fileName; /// - /// Creates a new instance with + /// Creates a new instance with /// the provided and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. - internal VirtualFile(string fileName, string? contentType) + internal VirtualFileHttpResult(string fileName, string? contentType) : this(fileName, contentType, fileDownloadName: null) { } /// - /// Creates a new instance with + /// Creates a new instance with /// the provided , the provided /// and the provided . /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. /// The suggested file name. - internal VirtualFile( + internal VirtualFileHttpResult( string fileName, string? contentType, string? fileDownloadName) @@ -46,7 +46,7 @@ internal VirtualFile( } /// - /// Creates a new instance with the provided values. + /// Creates a new instance with the provided values. /// /// The path to the file. The path must be an absolute path. /// The Content-Type header of the response. @@ -54,7 +54,7 @@ internal VirtualFile( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - internal VirtualFile( + internal VirtualFileHttpResult( string fileName, string? contentType, string? fileDownloadName, diff --git a/src/Http/Http.Results/test/ChallengeResultTests.cs b/src/Http/Http.Results/test/ChallengeResultTests.cs index c1da91476a72..a5d02031d54d 100644 --- a/src/Http/Http.Results/test/ChallengeResultTests.cs +++ b/src/Http/Http.Results/test/ChallengeResultTests.cs @@ -15,7 +15,7 @@ public class ChallengeResultTests public async Task ChallengeResult_ExecuteAsync() { // Arrange - var result = new Challenge("", null); + var result = new ChallengeHttpResult("", null); var auth = new Mock(); var httpContext = GetHttpContext(auth); @@ -30,7 +30,7 @@ public async Task ChallengeResult_ExecuteAsync() public async Task ChallengeResult_ExecuteAsync_NoSchemes() { // Arrange - var result = new Challenge(new string[] { }, null); + var result = new ChallengeHttpResult(new string[] { }, null); var auth = new Mock(); var httpContext = GetHttpContext(auth); diff --git a/src/Http/Http.Results/test/ContentResultTests.cs b/src/Http/Http.Results/test/ContentResultTests.cs index 8a3f742d7eb5..7b316c410981 100644 --- a/src/Http/Http.Results/test/ContentResultTests.cs +++ b/src/Http/Http.Results/test/ContentResultTests.cs @@ -20,7 +20,7 @@ public async Task ContentResult_ExecuteAsync_Response_NullContent_SetsContentTyp Encoding = Encoding.Unicode }.ToString(); - var contentResult = new Content(null, contentType); + var contentResult = new ContentHttpResult(null, contentType); var httpContext = GetHttpContext(); // Act @@ -107,7 +107,7 @@ public async Task ContentResult_ExecuteAsync_SetContentTypeAndEncoding_OnRespons byte[] expectedContentData) { // Arrange - var contentResult = new Content(content, contentType?.ToString()); + var contentResult = new ContentHttpResult(content, contentType?.ToString()); var httpContext = GetHttpContext(); var memoryStream = new MemoryStream(); httpContext.Response.Body = memoryStream; diff --git a/src/Http/Http.Results/test/EmptyResultTests.cs b/src/Http/Http.Results/test/EmptyResultTests.cs index 44ac64bee281..cde7fde64971 100644 --- a/src/Http/Http.Results/test/EmptyResultTests.cs +++ b/src/Http/Http.Results/test/EmptyResultTests.cs @@ -11,7 +11,7 @@ public class EmptyResultTests public async Task EmptyResult_DoesNothing() { // Arrange - var emptyResult = Empty.Instance; + var emptyResult = EmptyHttpResult.Instance; // Act var httpContext = GetHttpContext(); diff --git a/src/Http/Http.Results/test/FileContentResultTests.cs b/src/Http/Http.Results/test/FileContentResultTests.cs index 15d746f1f912..eba9c1ead376 100644 --- a/src/Http/Http.Results/test/FileContentResultTests.cs +++ b/src/Http/Http.Results/test/FileContentResultTests.cs @@ -19,7 +19,7 @@ protected override Task ExecuteAsync( EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { - var result = new FileContent(buffer, contentType) + var result = new FileContentHttpResult(buffer, contentType) { EntityTag = entityTag, LastModified = lastModified, diff --git a/src/Http/Http.Results/test/ForbidResultTests.cs b/src/Http/Http.Results/test/ForbidResultTests.cs index d4d5ee15cf97..ee58a6539e68 100644 --- a/src/Http/Http.Results/test/ForbidResultTests.cs +++ b/src/Http/Http.Results/test/ForbidResultTests.cs @@ -22,7 +22,7 @@ public async Task ExecuteResultAsync_InvokesForbidAsyncOnAuthenticationService() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new Forbid("", null); + var result = new ForbidHttpResult("", null); // Act await result.ExecuteAsync(httpContext); @@ -46,7 +46,7 @@ public async Task ExecuteResultAsync_InvokesForbidAsyncOnAllConfiguredSchemes() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new Forbid(new[] { "Scheme1", "Scheme2" }, authProperties); + var result = new ForbidHttpResult(new[] { "Scheme1", "Scheme2" }, authProperties); var routeData = new RouteData(); // Act @@ -73,7 +73,7 @@ public async Task ExecuteResultAsync_InvokesForbidAsyncWithAuthProperties(Authen .Setup(c => c.ForbidAsync(It.IsAny(), null, expected)) .Returns(Task.CompletedTask) .Verifiable(); - var result = new Forbid(expected); + var result = new ForbidHttpResult(expected); var httpContext = GetHttpContext(auth.Object); // Act @@ -95,7 +95,7 @@ public async Task ExecuteResultAsync_InvokesForbidAsyncWithAuthProperties_WhenAu .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new Forbid(expected) + var result = new ForbidHttpResult(expected) { AuthenticationSchemes = new string[0] }; diff --git a/src/Http/Http.Results/test/HttpFileStreamResultTests.cs b/src/Http/Http.Results/test/HttpFileStreamResultTests.cs index fd9d60b9e121..40cbc188ee54 100644 --- a/src/Http/Http.Results/test/HttpFileStreamResultTests.cs +++ b/src/Http/Http.Results/test/HttpFileStreamResultTests.cs @@ -16,7 +16,7 @@ protected override Task ExecuteAsync( EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { - var fileStreamResult = new HttpFileStream(stream, contentType) + var fileStreamResult = new FileStreamHttpResult(stream, contentType) { LastModified = lastModified, EntityTag = entityTag, @@ -33,7 +33,7 @@ public void Constructor_SetsFileName() var stream = Stream.Null; // Act - var result = new HttpFileStream(stream, "text/plain"); + var result = new FileStreamHttpResult(stream, "text/plain"); // Assert Assert.Equal(stream, result.FileStream); @@ -48,7 +48,7 @@ public void Constructor_SetsContentTypeAndParameters() var expectedMediaType = contentType; // Act - var result = new HttpFileStream(stream, contentType); + var result = new FileStreamHttpResult(stream, contentType); // Assert Assert.Equal(stream, result.FileStream); @@ -66,7 +66,7 @@ public void Constructor_SetsLastModifiedAndEtag() var entityTag = new EntityTagHeaderValue("\"Etag\""); // Act - var result = new HttpFileStream(stream, contentType) + var result = new FileStreamHttpResult(stream, contentType) { LastModified = lastModified, EntityTag = entityTag, diff --git a/src/Http/Http.Results/test/JsonResultTests.cs b/src/Http/Http.Results/test/JsonResultTests.cs index 263d8790b6c7..09f90d04fa3d 100644 --- a/src/Http/Http.Results/test/JsonResultTests.cs +++ b/src/Http/Http.Results/test/JsonResultTests.cs @@ -16,7 +16,7 @@ public class JsonResultTests public async Task JsonResult_ExecuteAsync_WithNullValue_Works() { // Arrange - var result = new Json(value: null, statusCode: 411, jsonSerializerOptions: null); + var result = new JsonHttpResult(value: null, statusCode: 411, jsonSerializerOptions: null); var httpContext = new DefaultHttpContext() { @@ -34,7 +34,7 @@ public async Task JsonResult_ExecuteAsync_WithNullValue_Works() public async Task JsonResult_ExecuteAsync_SetsStatusCode() { // Arrange - var result = new Json(value: null, statusCode: 407, jsonSerializerOptions: null); + var result = new JsonHttpResult(value: null, statusCode: 407, jsonSerializerOptions: null); var httpContext = new DefaultHttpContext() { @@ -52,7 +52,7 @@ public async Task JsonResult_ExecuteAsync_SetsStatusCode() public async Task JsonResult_ExecuteAsync_JsonSerializesBody() { // Arrange - var result = new Json(value: "Hello", statusCode: 407, jsonSerializerOptions: null); + var result = new JsonHttpResult(value: "Hello", statusCode: 407, jsonSerializerOptions: null); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -80,7 +80,7 @@ public async Task JsonResult_ExecuteAsync_JsonSerializesBody_WitOptions() DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull }; var value = new Todo(10, "MyName") { Description = null }; - var result = new Json(value, jsonSerializerOptions: jsonOptions); + var result = new JsonHttpResult(value, jsonSerializerOptions: jsonOptions); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -113,7 +113,7 @@ public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() // Arrange var details = new ProblemDetails(); - var result = new Json(details, jsonSerializerOptions: null); + var result = new JsonHttpResult(details, jsonSerializerOptions: null); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -142,7 +142,7 @@ public async Task ExecuteAsync_UsesDefaults_ForValidationProblemDetails() // Arrange var details = new HttpValidationProblemDetails(); - var result = new Json(details, jsonSerializerOptions: null); + var result = new JsonHttpResult(details, jsonSerializerOptions: null); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -171,7 +171,7 @@ public async Task ExecuteAsync_SetsProblemDetailsStatus_ForValidationProblemDeta // Arrange var details = new HttpValidationProblemDetails(); - var result = new Json(details, StatusCodes.Status422UnprocessableEntity, jsonSerializerOptions: null); + var result = new JsonHttpResult(details, StatusCodes.Status422UnprocessableEntity, jsonSerializerOptions: null); var httpContext = new DefaultHttpContext() { RequestServices = CreateServices(), @@ -190,7 +190,7 @@ public async Task ExecuteAsync_GetsStatusCodeFromProblemDetails() // Arrange var details = new ProblemDetails { Status = StatusCodes.Status413RequestEntityTooLarge, }; - var result = new Json(details, jsonSerializerOptions: null); + var result = new JsonHttpResult(details, jsonSerializerOptions: null); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/LocalRedirectResultTests.cs b/src/Http/Http.Results/test/LocalRedirectResultTests.cs index 42372d821e5c..982d0dbc0ceb 100644 --- a/src/Http/Http.Results/test/LocalRedirectResultTests.cs +++ b/src/Http/Http.Results/test/LocalRedirectResultTests.cs @@ -16,7 +16,7 @@ public void Constructor_WithParameterUrl_SetsResultUrlAndNotPermanentOrPreserveM var url = "/test/url"; // Act - var result = new Redirect(url, acceptLocalUrlOnly: true, false, false); + var result = new RedirectHttpResult(url, acceptLocalUrlOnly: true, false, false); // Assert Assert.False(result.PreserveMethod); @@ -31,7 +31,7 @@ public void Constructor_WithParameterUrlAndPermanent_SetsResultUrlAndPermanentNo var url = "/test/url"; // Act - var result = new Redirect(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: false); + var result = new RedirectHttpResult(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: false); // Assert Assert.False(result.PreserveMethod); @@ -46,7 +46,7 @@ public void Constructor_WithParameterUrlAndPermanent_SetsResultUrlPermanentAndPr var url = "/test/url"; // Act - var result = new Redirect(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: true); + var result = new RedirectHttpResult(url, acceptLocalUrlOnly: true, permanent: true, preserveMethod: true); // Assert Assert.True(result.PreserveMethod); @@ -63,7 +63,7 @@ public async Task Execute_ReturnsExpectedValues() var expectedPath = "/Home/About"; var httpContext = GetHttpContext(appRoot); - var result = new Redirect(contentPath, acceptLocalUrlOnly: true, false, false); + var result = new RedirectHttpResult(contentPath, acceptLocalUrlOnly: true, false, false); // Act await result.ExecuteAsync(httpContext); @@ -86,7 +86,7 @@ public async Task Execute_Throws_ForNonLocalUrl( { // Arrange var httpContext = GetHttpContext(appRoot); - var result = new Redirect(contentPath, acceptLocalUrlOnly: true, false, false); + var result = new RedirectHttpResult(contentPath, acceptLocalUrlOnly: true, false, false); // Act & Assert var exception = await Assert.ThrowsAsync(() => result.ExecuteAsync(httpContext)); @@ -107,7 +107,7 @@ public async Task Execute_Throws_ForNonLocalUrlTilde( { // Arrange var httpContext = GetHttpContext(appRoot); - var result = new Redirect(contentPath, acceptLocalUrlOnly: true, false, false); + var result = new RedirectHttpResult(contentPath, acceptLocalUrlOnly: true, false, false); // Act & Assert var exception = await Assert.ThrowsAsync(() => result.ExecuteAsync(httpContext)); diff --git a/src/Http/Http.Results/test/PhysicalFileResultTest.cs b/src/Http/Http.Results/test/PhysicalFileResultTest.cs index f63d50f71f95..e1a4c18b5d4d 100644 --- a/src/Http/Http.Results/test/PhysicalFileResultTest.cs +++ b/src/Http/Http.Results/test/PhysicalFileResultTest.cs @@ -16,7 +16,7 @@ protected override Task ExecuteAsync( EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { - var fileResult = new PhysicalFile(path, contentType) + var fileResult = new PhysicalFileHttpResult(path, contentType) { LastModified = lastModified, EntityTag = entityTag, diff --git a/src/Http/Http.Results/test/ProblemResultTests.cs b/src/Http/Http.Results/test/ProblemResultTests.cs index f394f3d71328..35bf6ea7ba27 100644 --- a/src/Http/Http.Results/test/ProblemResultTests.cs +++ b/src/Http/Http.Results/test/ProblemResultTests.cs @@ -17,7 +17,7 @@ public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() // Arrange var details = new ProblemDetails(); - var result = new Problem(details); + var result = new ProblemHttpResult(details); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -46,7 +46,7 @@ public async Task ExecuteAsync_UsesDefaults_ForValidationProblemDetails() // Arrange var details = new HttpValidationProblemDetails(); - var result = new Problem(details); + var result = new ProblemHttpResult(details); var stream = new MemoryStream(); var httpContext = new DefaultHttpContext() { @@ -75,7 +75,7 @@ public async Task ExecuteAsync_GetsStatusCodeFromProblemDetails() // Arrange var details = new ProblemDetails { Status = StatusCodes.Status413RequestEntityTooLarge, }; - var result = new Problem(details); + var result = new ProblemHttpResult(details); var httpContext = new DefaultHttpContext() { diff --git a/src/Http/Http.Results/test/PushStreamResultTests.cs b/src/Http/Http.Results/test/PushStreamResultTests.cs index 7460c6dc988d..669720f87f44 100644 --- a/src/Http/Http.Results/test/PushStreamResultTests.cs +++ b/src/Http/Http.Results/test/PushStreamResultTests.cs @@ -12,7 +12,7 @@ public class PushStreamResultTests [Fact] public async Task PushStreamResultsExposeTheResponseBody() { - var result = new PushStream(body => body.WriteAsync(Encoding.UTF8.GetBytes("Hello World").AsMemory()).AsTask(), contentType: null); + var result = new PushStreamHttpResult(body => body.WriteAsync(Encoding.UTF8.GetBytes("Hello World").AsMemory()).AsTask(), contentType: null); var httpContext = new DefaultHttpContext { @@ -37,7 +37,7 @@ public void Constructor_SetsContentTypeAndParameters() var callback = (Stream body) => body.WriteAsync(Encoding.UTF8.GetBytes("Hello World").AsMemory()).AsTask(); // Act - var result = new PushStream(callback, contentType); + var result = new PushStreamHttpResult(callback, contentType); // Assert Assert.Equal(expectedMediaType, result.ContentType); @@ -55,7 +55,7 @@ public void Constructor_SetsLastModifiedAndEtag() var callback = (Stream body) => body.WriteAsync(Encoding.UTF8.GetBytes("Hello World").AsMemory()).AsTask(); // Act - var result = new PushStream(callback, contentType) + var result = new PushStreamHttpResult(callback, contentType) { LastModified = lastModified, EntityTag = entityTag, diff --git a/src/Http/Http.Results/test/RedirectResultTests.cs b/src/Http/Http.Results/test/RedirectResultTests.cs index 18632b675683..8690e68a5be4 100644 --- a/src/Http/Http.Results/test/RedirectResultTests.cs +++ b/src/Http/Http.Results/test/RedirectResultTests.cs @@ -14,7 +14,7 @@ public void RedirectResult_Constructor_WithParameterUrlPermanentAndPreservesMeth var url = "/test/url"; // Act - var result = new Redirect(url, permanent: true, preserveMethod: true); + var result = new RedirectHttpResult(url, permanent: true, preserveMethod: true); // Assert Assert.True(result.PreserveMethod); @@ -24,7 +24,7 @@ public void RedirectResult_Constructor_WithParameterUrlPermanentAndPreservesMeth protected override Task ExecuteAsync(HttpContext httpContext, string contentPath) { - var redirectResult = new Redirect(contentPath, false, false); + var redirectResult = new RedirectHttpResult(contentPath, false, false); return redirectResult.ExecuteAsync(httpContext); } } diff --git a/src/Http/Http.Results/test/RedirectToRouteResultTests.cs b/src/Http/Http.Results/test/RedirectToRouteResultTests.cs index b2e404893229..d7f27a5561da 100644 --- a/src/Http/Http.Results/test/RedirectToRouteResultTests.cs +++ b/src/Http/Http.Results/test/RedirectToRouteResultTests.cs @@ -18,7 +18,7 @@ public async Task RedirectToRoute_Execute_ThrowsOnNullUrl() var httpContext = new DefaultHttpContext(); httpContext.RequestServices = CreateServices(null).BuildServiceProvider(); - var result = new RedirectToRoute(null, new Dictionary()); + var result = new RedirectToRouteHttpResult(null, new Dictionary()); // Act & Assert await ExceptionAssert.ThrowsAsync( @@ -38,7 +38,7 @@ public async Task ExecuteResultAsync_UsesRouteName_ToGenerateLocationHeader() var httpContext = GetHttpContext(locationUrl); - var result = new RedirectToRoute(routeName, new { id = 10 }); + var result = new RedirectToRouteHttpResult(routeName, new { id = 10 }); // Act await result.ExecuteAsync(httpContext); @@ -56,7 +56,7 @@ public async Task ExecuteResultAsync_WithFragment_PassesCorrectValuesToRedirect( var expectedStatusCode = StatusCodes.Status301MovedPermanently; var httpContext = GetHttpContext(expectedUrl); - var result = new RedirectToRoute("Sample", null, true, "test"); + var result = new RedirectToRouteHttpResult("Sample", null, true, "test"); // Act await result.ExecuteAsync(httpContext); @@ -74,7 +74,7 @@ public async Task ExecuteResultAsync_WithFragment_PassesCorrectValuesToRedirect_ var expectedStatusCode = StatusCodes.Status308PermanentRedirect; var httpContext = GetHttpContext(expectedUrl); - var result = new RedirectToRoute("Sample", null, true, true, "test"); + var result = new RedirectToRouteHttpResult("Sample", null, true, true, "test"); // Act await result.ExecuteAsync(httpContext); diff --git a/src/Http/Http.Results/test/SignInResultTests.cs b/src/Http/Http.Results/test/SignInResultTests.cs index 268ebff1d0d5..3d4c4136740a 100644 --- a/src/Http/Http.Results/test/SignInResultTests.cs +++ b/src/Http/Http.Results/test/SignInResultTests.cs @@ -24,7 +24,7 @@ public async Task ExecuteAsync_InvokesSignInAsyncOnAuthenticationManager() .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignIn(principal, "", null); + var result = new SignInHttpResult(principal, "", null); // Act await result.ExecuteAsync(httpContext); @@ -44,7 +44,7 @@ public async Task ExecuteAsync_InvokesSignInAsyncOnAuthenticationManagerWithDefa .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignIn(principal); + var result = new SignInHttpResult(principal); // Act await result.ExecuteAsync(httpContext); @@ -65,7 +65,7 @@ public async Task ExecuteAsync_InvokesSignInAsyncOnConfiguredScheme() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignIn(principal, "Scheme1", authProperties); + var result = new SignInHttpResult(principal, "Scheme1", authProperties); // Act await result.ExecuteAsync(httpContext); diff --git a/src/Http/Http.Results/test/SignOutResultTests.cs b/src/Http/Http.Results/test/SignOutResultTests.cs index fd29c979e563..386b29e928b6 100644 --- a/src/Http/Http.Results/test/SignOutResultTests.cs +++ b/src/Http/Http.Results/test/SignOutResultTests.cs @@ -21,7 +21,7 @@ public async Task ExecuteAsync_NoArgsInvokesDefaultSignOut() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignOut(); + var result = new SignOutHttpResult(); // Act await result.ExecuteAsync(httpContext); @@ -40,7 +40,7 @@ public async Task ExecuteAsync_InvokesSignOutAsyncOnAuthenticationManager() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignOut("", null); + var result = new SignOutHttpResult("", null); // Act await result.ExecuteAsync(httpContext); @@ -64,7 +64,7 @@ public async Task ExecuteAsync_InvokesSignOutAsyncOnAllConfiguredSchemes() .Returns(Task.CompletedTask) .Verifiable(); var httpContext = GetHttpContext(auth.Object); - var result = new SignOut(new[] { "Scheme1", "Scheme2" }, authProperties); + var result = new SignOutHttpResult(new[] { "Scheme1", "Scheme2" }, authProperties); // Act await result.ExecuteAsync(httpContext); diff --git a/src/Http/Http.Results/test/StatusCodeResultTests.cs b/src/Http/Http.Results/test/StatusCodeResultTests.cs index 631378619e0c..4e28357b5b19 100644 --- a/src/Http/Http.Results/test/StatusCodeResultTests.cs +++ b/src/Http/Http.Results/test/StatusCodeResultTests.cs @@ -13,7 +13,7 @@ public class StatusCodeResultTests public void StatusCodeResult_ExecuteResultSetsResponseStatusCode() { // Arrange - var result = new Status(StatusCodes.Status404NotFound); + var result = new StatusCodeHttpResult(StatusCodes.Status404NotFound); var httpContext = GetHttpContext(); diff --git a/src/Http/Http.Results/test/UnauthorizedResultTests.cs b/src/Http/Http.Results/test/UnauthorizedResultTests.cs index fe6ce9979757..9f25870fea87 100644 --- a/src/Http/Http.Results/test/UnauthorizedResultTests.cs +++ b/src/Http/Http.Results/test/UnauthorizedResultTests.cs @@ -13,7 +13,7 @@ public class UnauthorizedResultTests public void UnauthorizedResult_InitializesStatusCode() { // Arrange & act - var result = new Unauthorized(); + var result = new UnauthorizedHttpResult(); // Assert Assert.Equal(StatusCodes.Status401Unauthorized, result.StatusCode); @@ -23,7 +23,7 @@ public void UnauthorizedResult_InitializesStatusCode() public void UnauthorizedResult_ExecuteResultSetsResponseStatusCode() { // Arrange - var result = new Unauthorized(); + var result = new UnauthorizedHttpResult(); var httpContext = GetHttpContext(); diff --git a/src/Http/Http.Results/test/VirtualFileResultTests.cs b/src/Http/Http.Results/test/VirtualFileResultTests.cs index 9dcf525ec858..04ad231a47db 100644 --- a/src/Http/Http.Results/test/VirtualFileResultTests.cs +++ b/src/Http/Http.Results/test/VirtualFileResultTests.cs @@ -10,7 +10,7 @@ public class VirtualFileResultTests : VirtualFileResultTestBase { protected override Task ExecuteAsync(HttpContext httpContext, string path, string contentType, DateTimeOffset? lastModified = null, EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false) { - var result = new VirtualFile(path, contentType) + var result = new VirtualFileHttpResult(path, contentType) { LastModified = lastModified, EntityTag = entityTag, diff --git a/src/Http/Http.Results/tools/ResultsOfTGenerator/Program.cs b/src/Http/Http.Results/tools/ResultsOfTGenerator/Program.cs index 6326fe6faca1..033e1f00e4de 100644 --- a/src/Http/Http.Results/tools/ResultsOfTGenerator/Program.cs +++ b/src/Http/Http.Results/tools/ResultsOfTGenerator/Program.cs @@ -64,7 +64,7 @@ static void GenerateClassFile(string classFilePath, int typeArgCount, bool inter writer.WriteLine(); // Namespace - writer.WriteLine("namespace Microsoft.AspNetCore.Http;"); + writer.WriteLine("namespace Microsoft.AspNetCore.Http.HttpResults;"); writer.WriteLine(); // Skip 1 as we don't have a Results class diff --git a/src/Http/samples/MinimalSample/Program.cs b/src/Http/samples/MinimalSample/Program.cs index 9e51fee2845a..df453dfb596c 100644 --- a/src/Http/samples/MinimalSample/Program.cs +++ b/src/Http/samples/MinimalSample/Program.cs @@ -44,7 +44,7 @@ app.MapGet("/problem-object", () => Results.Problem(new ProblemDetails() { Status = 500, Extensions = { { "traceId", "traceId123" } } })); -var errors = new Dictionary(); +var errors = new Dictionary() { { "Title", new[] { "The Title field is required." } } }; app.MapGet("/validation-problem", () => Results.ValidationProblem(errors, statusCode: 400, extensions: extensions)); @@ -52,6 +52,9 @@ app.MapGet("/validation-problem-object", () => Results.Problem(new HttpValidationProblemDetails(errors) { Status = 400, Extensions = { { "traceId", "traceId123" } } })); +app.MapGet("/validation-problem-typed", () => + Results.Typed.ValidationProblem(errors, extensions: extensions)); + app.Run(); internal record Todo(int Id, string Title); From 0ca66824ece456286eebbd7be526a2517a8ff0e1 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Wed, 13 Apr 2022 12:02:38 -0700 Subject: [PATCH 15/35] Make Results factory methods call through to TypedResults --- src/Http/Http.Results/src/Results.cs | 203 +++++----------------- src/Http/Http.Results/src/TypedResults.cs | 29 ++-- 2 files changed, 52 insertions(+), 180 deletions(-) diff --git a/src/Http/Http.Results/src/Results.cs b/src/Http/Http.Results/src/Results.cs index edab9a8624e4..f44dcfebdb5e 100644 --- a/src/Http/Http.Results/src/Results.cs +++ b/src/Http/Http.Results/src/Results.cs @@ -33,7 +33,7 @@ public static partial class Results public static IResult Challenge( AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new ChallengeHttpResult(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + => TypedResults.Challenge(properties, authenticationSchemes); /// /// Creates a that on execution invokes . @@ -51,7 +51,7 @@ public static IResult Challenge( /// a redirect to show a login page. /// public static IResult Forbid(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new ForbidHttpResult(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); + => TypedResults.Forbid(properties, authenticationSchemes); /// /// Creates an that on execution invokes . @@ -64,7 +64,7 @@ public static IResult SignIn( ClaimsPrincipal principal, AuthenticationProperties? properties = null, string? authenticationScheme = null) - => new SignInHttpResult(principal, authenticationScheme, properties); + => TypedResults.SignIn(principal, properties, authenticationScheme); /// /// Creates an that on execution invokes . @@ -73,7 +73,7 @@ public static IResult SignIn( /// The authentication scheme to use for the sign-out operation. /// The created for the response. public static IResult SignOut(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) - => new SignOutHttpResult(authenticationSchemes ?? Array.Empty(), properties); + => TypedResults.SignOut(properties, authenticationSchemes); /// /// Writes the string to the HTTP response. @@ -90,7 +90,7 @@ public static IResult SignOut(AuthenticationProperties? properties = null, IList /// the parameter is chosen as the final encoding. /// public static IResult Content(string content, string? contentType = null, Encoding? contentEncoding = null) - => Text(content, contentType, contentEncoding); + => TypedResults.Content(content, contentType, contentEncoding); /// /// Writes the string to the HTTP response. @@ -107,16 +107,7 @@ public static IResult Content(string content, string? contentType = null, Encodi /// the parameter is chosen as the final encoding. /// public static IResult Text(string content, string? contentType = null, Encoding? contentEncoding = null) - { - MediaTypeHeaderValue? mediaTypeHeaderValue = null; - if (contentType is not null) - { - mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType); - mediaTypeHeaderValue.Encoding = contentEncoding ?? mediaTypeHeaderValue.Encoding; - } - - return new ContentHttpResult(content, mediaTypeHeaderValue?.ToString()); - } + => TypedResults.Text(content, contentType, contentEncoding); /// /// Writes the string to the HTTP response. @@ -125,7 +116,7 @@ public static IResult Text(string content, string? contentType = null, Encoding? /// The content type (MIME type). /// The created object for the response. public static IResult Content(string content, MediaTypeHeaderValue contentType) - => new ContentHttpResult(content, contentType.ToString()); + => TypedResults.Content(content, contentType); /// /// Creates a that serializes the specified object to JSON. @@ -139,10 +130,7 @@ public static IResult Content(string content, MediaTypeHeaderValue contentType) /// Callers should cache an instance of serializer settings to avoid /// recreating cached data with each call. public static IResult Json(object? data, JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) - => new JsonHttpResult(data, statusCode, options) - { - ContentType = contentType, - }; + => TypedResults.Json(data, options, contentType, statusCode); /// /// Writes the byte-array content to the response. @@ -163,19 +151,13 @@ public static IResult Json(object? data, JsonSerializerOptions? options = null, #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static IResult File( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - byte[] fileContents, + byte[] fileContents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - => new FileContentHttpResult(fileContents, contentType) - { - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - LastModified = lastModified, - EntityTag = entityTag, - }; + => TypedResults.File(fileContents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag); /// /// Writes the byte-array content to the response. @@ -200,13 +182,7 @@ public static IResult Bytes( bool enableRangeProcessing = false, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - => new FileContentHttpResult(contents, contentType) - { - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - LastModified = lastModified, - EntityTag = entityTag, - }; + => TypedResults.Bytes(contents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag); /// /// Writes the byte-array content to the response. @@ -231,13 +207,7 @@ public static IResult Bytes( bool enableRangeProcessing = false, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - => new FileContentHttpResult(contents, contentType) - { - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - LastModified = lastModified, - EntityTag = entityTag, - }; + => TypedResults.Bytes(contents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag); /// /// Writes the specified to the response. @@ -264,21 +234,13 @@ public static IResult Bytes( #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static IResult File( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - Stream fileStream, + Stream fileStream, string? contentType = null, string? fileDownloadName = null, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) - { - return new FileStreamHttpResult(fileStream, contentType) - { - LastModified = lastModified, - EntityTag = entityTag, - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - }; - } + => TypedResults.File(fileStream, contentType, fileDownloadName, lastModified, entityTag, enableRangeProcessing); /// /// Writes the specified to the response. @@ -309,15 +271,7 @@ public static IResult Stream( DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) - { - return new FileStreamHttpResult(stream, contentType) - { - LastModified = lastModified, - EntityTag = entityTag, - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - }; - } + => TypedResults.Stream(stream, contentType, fileDownloadName, lastModified, entityTag, enableRangeProcessing); /// /// Writes the contents of specified to the response. @@ -347,15 +301,7 @@ public static IResult Stream( DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) - { - return new FileStreamHttpResult(pipeReader.AsStream(), contentType) - { - LastModified = lastModified, - EntityTag = entityTag, - FileDownloadName = fileDownloadName, - EnableRangeProcessing = enableRangeProcessing, - }; - } + => TypedResults.Stream(pipeReader, contentType, fileDownloadName, lastModified, entityTag, enableRangeProcessing); /// /// Allows writing directly to the response body. @@ -380,14 +326,7 @@ public static IResult Stream( string? fileDownloadName = null, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null) - { - return new PushStreamHttpResult(streamWriterCallback, contentType) - { - LastModified = lastModified, - EntityTag = entityTag, - FileDownloadName = fileDownloadName, - }; - } + => TypedResults.Stream(streamWriterCallback, contentType, fileDownloadName, lastModified, entityTag); /// /// Writes the file at the specified to the response. @@ -406,34 +345,15 @@ public static IResult Stream( #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static IResult File( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - string path, + string path, string? contentType = null, string? fileDownloadName = null, DateTimeOffset? lastModified = null, EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) - { - if (Path.IsPathRooted(path)) - { - return new PhysicalFileHttpResult(path, contentType) - { - FileDownloadName = fileDownloadName, - LastModified = lastModified, - EntityTag = entityTag, - EnableRangeProcessing = enableRangeProcessing, - }; - } - else - { - return new VirtualFileHttpResult(path, contentType) - { - FileDownloadName = fileDownloadName, - LastModified = lastModified, - EntityTag = entityTag, - EnableRangeProcessing = enableRangeProcessing, - }; - } - } + => Path.IsPathRooted(path) + ? TypedResults.PhysicalFile(path, contentType, fileDownloadName, lastModified, entityTag, enableRangeProcessing) + : TypedResults.VirtualFile(path, contentType, fileDownloadName, lastModified, entityTag, enableRangeProcessing); /// /// Redirects to the specified . @@ -449,7 +369,7 @@ public static IResult File( /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. /// The created for the response. public static IResult Redirect(string url, bool permanent = false, bool preserveMethod = false) - => new RedirectHttpResult(url, permanent, preserveMethod); + => TypedResults.Redirect(url, permanent, preserveMethod); /// /// Redirects to the specified . @@ -465,7 +385,7 @@ public static IResult Redirect(string url, bool permanent = false, bool preserve /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. /// The created for the response. public static IResult LocalRedirect(string localUrl, bool permanent = false, bool preserveMethod = false) - => new RedirectHttpResult(localUrl, acceptLocalUrlOnly: true, permanent, preserveMethod); + => TypedResults.LocalRedirect(localUrl, permanent, preserveMethod); /// /// Redirects to the specified route. @@ -483,12 +403,7 @@ public static IResult LocalRedirect(string localUrl, bool permanent = false, boo /// The fragment to add to the URL. /// The created for the response. public static IResult RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) - => new RedirectToRouteHttpResult( - routeName: routeName, - routeValues: routeValues, - permanent: permanent, - preserveMethod: preserveMethod, - fragment: fragment); + => TypedResults.RedirectToRoute(routeName, routeValues, permanent, preserveMethod, fragment); /// /// Creates a object by specifying a . @@ -496,7 +411,7 @@ public static IResult RedirectToRoute(string? routeName = null, object? routeVal /// The status code to set on the response. /// The created object for the response. public static IResult StatusCode(int statusCode) - => ResultsCache.StatusCode(statusCode); + => TypedResults.StatusCode(statusCode); /// /// Produces a response. @@ -504,14 +419,14 @@ public static IResult StatusCode(int statusCode) /// The value to be included in the HTTP response body. /// The created for the response. public static IResult NotFound(object? value = null) - => value is null ? ResultsCache.NotFound : new NotFound(value); + => value is null ? TypedResults.NotFound() : TypedResults.NotFound(value); /// /// Produces a response. /// /// The created for the response. public static IResult Unauthorized() - => ResultsCache.Unauthorized; + => TypedResults.Unauthorized(); /// /// Produces a response. @@ -519,7 +434,7 @@ public static IResult Unauthorized() /// An error object to be included in the HTTP response body. /// The created for the response. public static IResult BadRequest(object? error = null) - => error is null ? ResultsCache.BadRequest : new BadRequest(error); + => error is null ? TypedResults.BadRequest() : TypedResults.BadRequest(error); /// /// Produces a response. @@ -527,14 +442,14 @@ public static IResult BadRequest(object? error = null) /// An error object to be included in the HTTP response body. /// The created for the response. public static IResult Conflict(object? error = null) - => error is null ? ResultsCache.Conflict : new Conflict(error); + => error is null ? TypedResults.Conflict() : TypedResults.Conflict(error); /// /// Produces a response. /// /// The created for the response. public static IResult NoContent() - => ResultsCache.NoContent; + => TypedResults.NoContent(); /// /// Produces a response. @@ -542,7 +457,7 @@ public static IResult NoContent() /// The value to be included in the HTTP response body. /// The created for the response. public static IResult Ok(object? value = null) - => value is null ? ResultsCache.Ok : new Ok(value); + => value is null ? TypedResults.Ok() : TypedResults.Ok(value); /// /// Produces a response. @@ -550,7 +465,7 @@ public static IResult Ok(object? value = null) /// An error object to be included in the HTTP response body. /// The created for the response. public static IResult UnprocessableEntity(object? error = null) - => error is null ? ResultsCache.UnprocessableEntity : new UnprocessableEntity(error); + => error is null ? TypedResults.UnprocessableEntity() : TypedResults.UnprocessableEntity(error); /// /// Produces a response. @@ -569,26 +484,7 @@ public static IResult Problem( string? title = null, string? type = null, IDictionary? extensions = null) - { - var problemDetails = new ProblemDetails - { - Detail = detail, - Instance = instance, - Status = statusCode, - Title = title, - Type = type, - }; - - if (extensions is not null) - { - foreach (var extension in extensions) - { - problemDetails.Extensions.Add(extension); - } - } - - return new ProblemHttpResult(problemDetails); - } + => TypedResults.Problem(detail, instance, statusCode, title, type, extensions); /// /// Produces a response. @@ -596,9 +492,7 @@ public static IResult Problem( /// The object to produce a response from. /// The created for the response. public static IResult Problem(ProblemDetails problemDetails) - { - return new ProblemHttpResult(problemDetails); - } + => TypedResults.Problem(problemDetails); /// /// Produces a response @@ -621,6 +515,7 @@ public static IResult ValidationProblem( string? type = null, IDictionary? extensions = null) { + // TypedResults.ValidationProblem() does not allow setting the statusCode so we do this manually here var problemDetails = new HttpValidationProblemDetails(errors) { Detail = detail, @@ -639,7 +534,7 @@ public static IResult ValidationProblem( } } - return new ProblemHttpResult(problemDetails); + return TypedResults.Problem(problemDetails); } /// @@ -649,14 +544,7 @@ public static IResult ValidationProblem( /// The value to be included in the HTTP response body. /// The created for the response. public static IResult Created(string uri, object? value) - { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } - - return new Created(uri, value); - } + => value is null ? TypedResults.Created(uri) : TypedResults.Created(uri, value); /// /// Produces a response. @@ -665,14 +553,7 @@ public static IResult Created(string uri, object? value) /// The value to be included in the HTTP response body. /// The created for the response. public static IResult Created(Uri uri, object? value) - { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } - - return new Created(uri, value); - } + => value is null ? TypedResults.Created(uri) : TypedResults.Created(uri, value); /// /// Produces a response. @@ -682,7 +563,7 @@ public static IResult Created(Uri uri, object? value) /// The value to be included in the HTTP response body. /// The created for the response. public static IResult CreatedAtRoute(string? routeName = null, object? routeValues = null, object? value = null) - => new CreatedAtRoute(routeName, routeValues, value); + => value is null ? TypedResults.CreatedAtRoute(routeName, routeValues) : TypedResults.CreatedAtRoute(value, routeName, routeValues); /// /// Produces a response. @@ -691,7 +572,7 @@ public static IResult CreatedAtRoute(string? routeName = null, object? routeValu /// The optional content value to format in the response body. /// The created for the response. public static IResult Accepted(string? uri = null, object? value = null) - => new Accepted(uri, value); + => value is null ? TypedResults.Accepted(uri) : TypedResults.Accepted(uri, value); /// /// Produces a response. @@ -701,12 +582,12 @@ public static IResult Accepted(string? uri = null, object? value = null) /// The optional content value to format in the response body. /// The created for the response. public static IResult AcceptedAtRoute(string? routeName = null, object? routeValues = null, object? value = null) - => new AcceptedAtRoute(routeName, routeValues, value); + => value is null ? TypedResults.AcceptedAtRoute(routeName, routeValues) : TypedResults.AcceptedAtRoute(value, routeName, routeValues); /// /// Produces an empty result response, that when executed will do nothing. /// - public static IResult Empty { get; } = HttpResults.EmptyHttpResult.Instance; + public static IResult Empty { get; } = TypedResults.Empty; /// /// Provides a container for external libraries to extend diff --git a/src/Http/Http.Results/src/TypedResults.cs b/src/Http/Http.Results/src/TypedResults.cs index 06912c0a2a4e..78bceaebbb09 100644 --- a/src/Http/Http.Results/src/TypedResults.cs +++ b/src/Http/Http.Results/src/TypedResults.cs @@ -267,7 +267,7 @@ public static FileContentHttpResult Bytes( #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static FileStreamHttpResult File( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - Stream fileStream, + Stream fileStream, string? contentType = null, string? fileDownloadName = null, DateTimeOffset? lastModified = null, @@ -784,15 +784,8 @@ public static CreatedAtRoute CreatedAtRoute(TValue? value, strin /// /// The URI with the location at which the status of requested content can be monitored. /// The created for the response. - public static Accepted Accepted(string uri) - { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } - - return new(uri); - } + public static Accepted Accepted(string? uri) + => new(uri); /// /// Produces a response. @@ -801,15 +794,8 @@ public static Accepted Accepted(string uri) /// The URI with the location at which the status of requested content can be monitored. /// The value to be included in the HTTP response body. /// The created for the response. - public static Accepted Accepted(string uri, TValue? value) - { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } - - return new(uri, value); - } + public static Accepted Accepted(string? uri, TValue? value) + => new(uri, value); /// /// Produces a response. @@ -866,4 +852,9 @@ public static AcceptedAtRoute AcceptedAtRoute(string? routeName = null, object? public static AcceptedAtRoute AcceptedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters => new(routeName, routeValues, value); + + /// + /// Produces an empty result response, that when executed will do nothing. + /// + public static EmptyHttpResult Empty { get; } = EmptyHttpResult.Instance; } From 40e5e2cb0234f658a2c001338cb038e65c264fa7 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Wed, 13 Apr 2022 13:37:41 -0700 Subject: [PATCH 16/35] Fix docs & PublicAPI --- .../Http.Results/src/PublicAPI.Unshipped.txt | 324 ++++++++++-------- src/Http/Http.Results/src/TypedResults.cs | 144 ++++---- .../Http.Results/src/ValidationProblem.cs | 1 + 3 files changed, 263 insertions(+), 206 deletions(-) diff --git a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt index c6243c6aa0f7..b5debdbce0e3 100644 --- a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt @@ -26,10 +26,10 @@ Microsoft.AspNetCore.Http.HttpResults.BadRequest Microsoft.AspNetCore.Http.HttpResults.BadRequest.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.BadRequest.StatusCode.get -> int Microsoft.AspNetCore.Http.HttpResults.BadRequest.Value.get -> TValue? -Microsoft.AspNetCore.Http.HttpResults.Challenge -Microsoft.AspNetCore.Http.HttpResults.Challenge.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! -Microsoft.AspNetCore.Http.HttpResults.Challenge.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.Challenge.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? +Microsoft.AspNetCore.Http.HttpResults.ChallengeHttpResult +Microsoft.AspNetCore.Http.HttpResults.ChallengeHttpResult.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! +Microsoft.AspNetCore.Http.HttpResults.ChallengeHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.ChallengeHttpResult.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? Microsoft.AspNetCore.Http.HttpResults.Conflict Microsoft.AspNetCore.Http.HttpResults.Conflict.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.Conflict.StatusCode.get -> int @@ -37,11 +37,11 @@ Microsoft.AspNetCore.Http.HttpResults.Conflict Microsoft.AspNetCore.Http.HttpResults.Conflict.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.Conflict.StatusCode.get -> int Microsoft.AspNetCore.Http.HttpResults.Conflict.Value.get -> TValue? -Microsoft.AspNetCore.Http.HttpResults.Content -Microsoft.AspNetCore.Http.HttpResults.Content.ContentType.get -> string? -Microsoft.AspNetCore.Http.HttpResults.Content.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.Content.ResponseContent.get -> string? -Microsoft.AspNetCore.Http.HttpResults.Content.StatusCode.get -> int? +Microsoft.AspNetCore.Http.HttpResults.ContentHttpResult +Microsoft.AspNetCore.Http.HttpResults.ContentHttpResult.ContentType.get -> string? +Microsoft.AspNetCore.Http.HttpResults.ContentHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.ContentHttpResult.ResponseContent.get -> string? +Microsoft.AspNetCore.Http.HttpResults.ContentHttpResult.StatusCode.get -> int? Microsoft.AspNetCore.Http.HttpResults.Created Microsoft.AspNetCore.Http.HttpResults.Created.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.Created.Location.get -> string? @@ -62,36 +62,36 @@ Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteName.get -> st Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.StatusCode.get -> int Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.Value.get -> TValue? -Microsoft.AspNetCore.Http.HttpResults.Empty -Microsoft.AspNetCore.Http.HttpResults.Empty.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.FileContent -Microsoft.AspNetCore.Http.HttpResults.FileContent.ContentType.get -> string! -Microsoft.AspNetCore.Http.HttpResults.FileContent.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.HttpResults.FileContent.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.HttpResults.FileContent.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.FileContent.FileContents.get -> System.ReadOnlyMemory -Microsoft.AspNetCore.Http.HttpResults.FileContent.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.HttpResults.FileContent.FileLength.get -> long? -Microsoft.AspNetCore.Http.HttpResults.FileContent.LastModified.get -> System.DateTimeOffset? -Microsoft.AspNetCore.Http.HttpResults.Forbid -Microsoft.AspNetCore.Http.HttpResults.Forbid.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! -Microsoft.AspNetCore.Http.HttpResults.Forbid.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.Forbid.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? -Microsoft.AspNetCore.Http.HttpResults.HttpFileStream -Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.ContentType.get -> string! -Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.FileLength.get -> long? -Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.FileStream.get -> System.IO.Stream! -Microsoft.AspNetCore.Http.HttpResults.HttpFileStream.LastModified.get -> System.DateTimeOffset? -Microsoft.AspNetCore.Http.HttpResults.Json -Microsoft.AspNetCore.Http.HttpResults.Json.ContentType.get -> string? -Microsoft.AspNetCore.Http.HttpResults.Json.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.Json.JsonSerializerOptions.get -> System.Text.Json.JsonSerializerOptions? -Microsoft.AspNetCore.Http.HttpResults.Json.StatusCode.get -> int? -Microsoft.AspNetCore.Http.HttpResults.Json.Value.get -> TValue? +Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult +Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult +Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult.FileContents.get -> System.ReadOnlyMemory +Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult +Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult.FileStream.get -> System.IO.Stream! +Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.HttpResults.ForbidHttpResult +Microsoft.AspNetCore.Http.HttpResults.ForbidHttpResult.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! +Microsoft.AspNetCore.Http.HttpResults.ForbidHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.ForbidHttpResult.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? +Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult +Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult.ContentType.get -> string? +Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult.JsonSerializerOptions.get -> System.Text.Json.JsonSerializerOptions? +Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult.StatusCode.get -> int? +Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult.Value.get -> TValue? Microsoft.AspNetCore.Http.HttpResults.NoContent Microsoft.AspNetCore.Http.HttpResults.NoContent.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.NoContent.StatusCode.get -> int @@ -109,56 +109,71 @@ Microsoft.AspNetCore.Http.HttpResults.Ok Microsoft.AspNetCore.Http.HttpResults.Ok.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.Ok.StatusCode.get -> int Microsoft.AspNetCore.Http.HttpResults.Ok.Value.get -> TValue? -Microsoft.AspNetCore.Http.HttpResults.PhysicalFile -Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.ContentType.get -> string! -Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.FileLength.get -> long? -Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.FileName.get -> string! -Microsoft.AspNetCore.Http.HttpResults.PhysicalFile.LastModified.get -> System.DateTimeOffset? -Microsoft.AspNetCore.Http.HttpResults.Problem -Microsoft.AspNetCore.Http.HttpResults.Problem.ContentType.get -> string! -Microsoft.AspNetCore.Http.HttpResults.Problem.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.Problem.ProblemDetails.get -> Microsoft.AspNetCore.Mvc.ProblemDetails! -Microsoft.AspNetCore.Http.HttpResults.Problem.StatusCode.get -> int? -Microsoft.AspNetCore.Http.HttpResults.PushStream -Microsoft.AspNetCore.Http.HttpResults.PushStream.ContentType.get -> string! -Microsoft.AspNetCore.Http.HttpResults.PushStream.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.HttpResults.PushStream.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.HttpResults.PushStream.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.PushStream.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.HttpResults.PushStream.FileLength.get -> long? -Microsoft.AspNetCore.Http.HttpResults.PushStream.LastModified.get -> System.DateTimeOffset? -Microsoft.AspNetCore.Http.HttpResults.Redirect -Microsoft.AspNetCore.Http.HttpResults.Redirect.AcceptLocalUrlOnly.get -> bool -Microsoft.AspNetCore.Http.HttpResults.Redirect.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.Redirect.Permanent.get -> bool -Microsoft.AspNetCore.Http.HttpResults.Redirect.PreserveMethod.get -> bool -Microsoft.AspNetCore.Http.HttpResults.Redirect.Url.get -> string! -Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute -Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.Fragment.get -> string? -Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.Permanent.get -> bool -Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.PreserveMethod.get -> bool -Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.RouteName.get -> string? -Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? -Microsoft.AspNetCore.Http.HttpResults.SignIn -Microsoft.AspNetCore.Http.HttpResults.SignIn.AuthenticationScheme.get -> string? -Microsoft.AspNetCore.Http.HttpResults.SignIn.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.SignIn.Principal.get -> System.Security.Claims.ClaimsPrincipal! -Microsoft.AspNetCore.Http.HttpResults.SignIn.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? -Microsoft.AspNetCore.Http.HttpResults.SignOut -Microsoft.AspNetCore.Http.HttpResults.SignOut.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! -Microsoft.AspNetCore.Http.HttpResults.SignOut.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.SignOut.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? -Microsoft.AspNetCore.Http.HttpResults.Status -Microsoft.AspNetCore.Http.HttpResults.Status.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.Status.StatusCode.get -> int -Microsoft.AspNetCore.Http.HttpResults.Unauthorized -Microsoft.AspNetCore.Http.HttpResults.Unauthorized.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.Unauthorized.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult +Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult.FileName.get -> string! +Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.HttpResults.ProblemHttpResult +Microsoft.AspNetCore.Http.HttpResults.ProblemHttpResult.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.ProblemHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.ProblemHttpResult.ProblemDetails.get -> Microsoft.AspNetCore.Mvc.ProblemDetails! +Microsoft.AspNetCore.Http.HttpResults.ProblemHttpResult.StatusCode.get -> int? +Microsoft.AspNetCore.Http.HttpResults.PushStreamHttpResult +Microsoft.AspNetCore.Http.HttpResults.PushStreamHttpResult.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.PushStreamHttpResult.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.PushStreamHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.PushStreamHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.PushStreamHttpResult.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.PushStreamHttpResult.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.PushStreamHttpResult.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.HttpResults.RedirectHttpResult +Microsoft.AspNetCore.Http.HttpResults.RedirectHttpResult.AcceptLocalUrlOnly.get -> bool +Microsoft.AspNetCore.Http.HttpResults.RedirectHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.RedirectHttpResult.Permanent.get -> bool +Microsoft.AspNetCore.Http.HttpResults.RedirectHttpResult.PreserveMethod.get -> bool +Microsoft.AspNetCore.Http.HttpResults.RedirectHttpResult.Url.get -> string! +Microsoft.AspNetCore.Http.HttpResults.RedirectToRouteHttpResult +Microsoft.AspNetCore.Http.HttpResults.RedirectToRouteHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.RedirectToRouteHttpResult.Fragment.get -> string? +Microsoft.AspNetCore.Http.HttpResults.RedirectToRouteHttpResult.Permanent.get -> bool +Microsoft.AspNetCore.Http.HttpResults.RedirectToRouteHttpResult.PreserveMethod.get -> bool +Microsoft.AspNetCore.Http.HttpResults.RedirectToRouteHttpResult.RouteName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.RedirectToRouteHttpResult.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? +Microsoft.AspNetCore.Http.HttpResults.Results +Microsoft.AspNetCore.Http.HttpResults.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! +Microsoft.AspNetCore.Http.HttpResults.Results +Microsoft.AspNetCore.Http.HttpResults.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! +Microsoft.AspNetCore.Http.HttpResults.Results +Microsoft.AspNetCore.Http.HttpResults.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! +Microsoft.AspNetCore.Http.HttpResults.Results +Microsoft.AspNetCore.Http.HttpResults.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! +Microsoft.AspNetCore.Http.HttpResults.Results +Microsoft.AspNetCore.Http.HttpResults.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! +Microsoft.AspNetCore.Http.HttpResults.SignInHttpResult +Microsoft.AspNetCore.Http.HttpResults.SignInHttpResult.AuthenticationScheme.get -> string? +Microsoft.AspNetCore.Http.HttpResults.SignInHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.SignInHttpResult.Principal.get -> System.Security.Claims.ClaimsPrincipal! +Microsoft.AspNetCore.Http.HttpResults.SignInHttpResult.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? +Microsoft.AspNetCore.Http.HttpResults.SignOutHttpResult +Microsoft.AspNetCore.Http.HttpResults.SignOutHttpResult.AuthenticationSchemes.get -> System.Collections.Generic.IReadOnlyList! +Microsoft.AspNetCore.Http.HttpResults.SignOutHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.SignOutHttpResult.Properties.get -> Microsoft.AspNetCore.Authentication.AuthenticationProperties? +Microsoft.AspNetCore.Http.HttpResults.StatusCodeHttpResult +Microsoft.AspNetCore.Http.HttpResults.StatusCodeHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.StatusCodeHttpResult.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.UnauthorizedHttpResult +Microsoft.AspNetCore.Http.HttpResults.UnauthorizedHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.UnauthorizedHttpResult.StatusCode.get -> int Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.StatusCode.get -> int @@ -166,32 +181,44 @@ Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.StatusCode.get -> int Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity.Value.get -> TValue? -Microsoft.AspNetCore.Http.HttpResults.VirtualFile -Microsoft.AspNetCore.Http.HttpResults.VirtualFile.ContentType.get -> string! -Microsoft.AspNetCore.Http.HttpResults.VirtualFile.EnableRangeProcessing.get -> bool -Microsoft.AspNetCore.Http.HttpResults.VirtualFile.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? -Microsoft.AspNetCore.Http.HttpResults.VirtualFile.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.HttpResults.VirtualFile.FileDownloadName.get -> string? -Microsoft.AspNetCore.Http.HttpResults.VirtualFile.FileLength.get -> long? -Microsoft.AspNetCore.Http.HttpResults.VirtualFile.FileName.get -> string! -Microsoft.AspNetCore.Http.HttpResults.VirtualFile.LastModified.get -> System.DateTimeOffset? +Microsoft.AspNetCore.Http.HttpResults.ValidationProblem +Microsoft.AspNetCore.Http.HttpResults.ValidationProblem.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.ValidationProblem.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.ValidationProblem.ProblemDetails.get -> Microsoft.AspNetCore.Http.HttpValidationProblemDetails! +Microsoft.AspNetCore.Http.HttpResults.ValidationProblem.StatusCode.get -> int +Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult +Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.ContentType.get -> string! +Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.EnableRangeProcessing.get -> bool +Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue? +Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! +Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.FileDownloadName.get -> string? +Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.FileLength.get -> long? +Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.FileName.get -> string! +Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.LastModified.get -> System.DateTimeOffset? Microsoft.AspNetCore.Http.Results.Typed -Microsoft.AspNetCore.Http.Results -Microsoft.AspNetCore.Http.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! -Microsoft.AspNetCore.Http.Results -Microsoft.AspNetCore.Http.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! -Microsoft.AspNetCore.Http.Results -Microsoft.AspNetCore.Http.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! -Microsoft.AspNetCore.Http.Results -Microsoft.AspNetCore.Http.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! -Microsoft.AspNetCore.Http.Results -Microsoft.AspNetCore.Http.Results.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! -Microsoft.AspNetCore.Http.Results.Result.get -> Microsoft.AspNetCore.Http.IResult! -static Microsoft.AspNetCore.Http.HttpResults.Empty.Instance.get -> Microsoft.AspNetCore.Http.HttpResults.Empty! +Microsoft.AspNetCore.Http.TypedResults +static Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult.Instance.get -> Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult4 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult5 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult6 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult4 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult5 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult4 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! +static Microsoft.AspNetCore.Http.HttpResults.ValidationProblem.PopulateMetadata(Microsoft.AspNetCore.Http.Metadata.EndpointMetadataContext! context) -> void static Microsoft.AspNetCore.Http.Results.Typed.Accepted(System.Uri! uri) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! static Microsoft.AspNetCore.Http.Results.Typed.Accepted(string! uri) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! static Microsoft.AspNetCore.Http.Results.Typed.Accepted(System.Uri! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! @@ -240,27 +267,56 @@ static Microsoft.AspNetCore.Http.Results.Typed.UnprocessableEntity() -> Microsof static Microsoft.AspNetCore.Http.Results.Typed.UnprocessableEntity(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity! static Microsoft.AspNetCore.Http.Results.Typed.ValidationProblem(System.Collections.Generic.IDictionary! errors, string? detail = null, string? instance = null, string? title = null, string? type = null, System.Collections.Generic.IDictionary? extensions = null) -> Microsoft.AspNetCore.Http.HttpResults.BadRequest! static Microsoft.AspNetCore.Http.Results.Typed.VirtualFile(string! path, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.VirtualFile! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult4 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult5 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult6 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult4 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult5 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult4 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.Results! -static Microsoft.AspNetCore.Http.Results.implicit operator Microsoft.AspNetCore.Http.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.Results! static Microsoft.AspNetCore.Http.Results.Bytes(System.ReadOnlyMemory contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.IResult! static Microsoft.AspNetCore.Http.Results.Empty.get -> Microsoft.AspNetCore.Http.IResult! static Microsoft.AspNetCore.Http.Results.Stream(System.Func! streamWriterCallback, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.IResult! static Microsoft.AspNetCore.Http.Results.Stream(System.IO.Pipelines.PipeReader! pipeReader, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.IResult! +static Microsoft.AspNetCore.Http.TypedResults.Accepted(System.Uri! uri) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! +static Microsoft.AspNetCore.Http.TypedResults.Accepted(string? uri) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! +static Microsoft.AspNetCore.Http.TypedResults.Accepted(System.Uri! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! +static Microsoft.AspNetCore.Http.TypedResults.Accepted(string? uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! +static Microsoft.AspNetCore.Http.TypedResults.AcceptedAtRoute(string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute! +static Microsoft.AspNetCore.Http.TypedResults.AcceptedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute! +static Microsoft.AspNetCore.Http.TypedResults.BadRequest() -> Microsoft.AspNetCore.Http.HttpResults.BadRequest! +static Microsoft.AspNetCore.Http.TypedResults.BadRequest(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.BadRequest! +static Microsoft.AspNetCore.Http.TypedResults.Bytes(System.ReadOnlyMemory contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Bytes(byte[]! contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Challenge(Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, System.Collections.Generic.IList? authenticationSchemes = null) -> Microsoft.AspNetCore.Http.HttpResults.ChallengeHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Conflict() -> Microsoft.AspNetCore.Http.HttpResults.Conflict! +static Microsoft.AspNetCore.Http.TypedResults.Conflict(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.Conflict! +static Microsoft.AspNetCore.Http.TypedResults.Content(string! content, Microsoft.Net.Http.Headers.MediaTypeHeaderValue! contentType) -> Microsoft.AspNetCore.Http.HttpResults.ContentHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Content(string! content, string? contentType = null, System.Text.Encoding? contentEncoding = null) -> Microsoft.AspNetCore.Http.HttpResults.ContentHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Created(System.Uri! uri) -> Microsoft.AspNetCore.Http.HttpResults.Created! +static Microsoft.AspNetCore.Http.TypedResults.Created(string! uri) -> Microsoft.AspNetCore.Http.HttpResults.Created! +static Microsoft.AspNetCore.Http.TypedResults.Created(System.Uri! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Created! +static Microsoft.AspNetCore.Http.TypedResults.Created(string! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Created! +static Microsoft.AspNetCore.Http.TypedResults.CreatedAtRoute(string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute! +static Microsoft.AspNetCore.Http.TypedResults.CreatedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute! +static Microsoft.AspNetCore.Http.TypedResults.Empty.get -> Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.File(System.IO.Stream! fileStream, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.File(byte[]! fileContents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.FileContentHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Forbid(Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, System.Collections.Generic.IList? authenticationSchemes = null) -> Microsoft.AspNetCore.Http.HttpResults.ForbidHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Json(TValue? data, System.Text.Json.JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) -> Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.LocalRedirect(string! localUrl, bool permanent = false, bool preserveMethod = false) -> Microsoft.AspNetCore.Http.HttpResults.RedirectHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.NoContent() -> Microsoft.AspNetCore.Http.HttpResults.NoContent! +static Microsoft.AspNetCore.Http.TypedResults.NotFound() -> Microsoft.AspNetCore.Http.HttpResults.NotFound! +static Microsoft.AspNetCore.Http.TypedResults.NotFound(TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.NotFound! +static Microsoft.AspNetCore.Http.TypedResults.Ok() -> Microsoft.AspNetCore.Http.HttpResults.Ok! +static Microsoft.AspNetCore.Http.TypedResults.Ok(TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Ok! +static Microsoft.AspNetCore.Http.TypedResults.PhysicalFile(string! path, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.PhysicalFileHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Problem(Microsoft.AspNetCore.Mvc.ProblemDetails! problemDetails) -> Microsoft.AspNetCore.Http.HttpResults.ProblemHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Problem(string? detail = null, string? instance = null, int? statusCode = null, string? title = null, string? type = null, System.Collections.Generic.IDictionary? extensions = null) -> Microsoft.AspNetCore.Http.HttpResults.ProblemHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Redirect(string! url, bool permanent = false, bool preserveMethod = false) -> Microsoft.AspNetCore.Http.HttpResults.RedirectHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) -> Microsoft.AspNetCore.Http.HttpResults.RedirectToRouteHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.SignIn(System.Security.Claims.ClaimsPrincipal! principal, Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, string? authenticationScheme = null) -> Microsoft.AspNetCore.Http.HttpResults.SignInHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.SignOut(Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, System.Collections.Generic.IList? authenticationSchemes = null) -> Microsoft.AspNetCore.Http.HttpResults.SignOutHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.StatusCode(int statusCode) -> Microsoft.AspNetCore.Http.HttpResults.StatusCodeHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Stream(System.Func! streamWriterCallback, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.PushStreamHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Stream(System.IO.Pipelines.PipeReader! pipeReader, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Stream(System.IO.Stream! stream, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.FileStreamHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Text(string! content, string? contentType = null, System.Text.Encoding? contentEncoding = null) -> Microsoft.AspNetCore.Http.HttpResults.ContentHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.Unauthorized() -> Microsoft.AspNetCore.Http.HttpResults.UnauthorizedHttpResult! +static Microsoft.AspNetCore.Http.TypedResults.UnprocessableEntity() -> Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity! +static Microsoft.AspNetCore.Http.TypedResults.UnprocessableEntity(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity! +static Microsoft.AspNetCore.Http.TypedResults.ValidationProblem(System.Collections.Generic.IDictionary! errors, string? detail = null, string? instance = null, string? title = null, string? type = null, System.Collections.Generic.IDictionary? extensions = null) -> Microsoft.AspNetCore.Http.HttpResults.ValidationProblem! +static Microsoft.AspNetCore.Http.TypedResults.VirtualFile(string! path, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult! diff --git a/src/Http/Http.Results/src/TypedResults.cs b/src/Http/Http.Results/src/TypedResults.cs index 78bceaebbb09..fb7edba9f999 100644 --- a/src/Http/Http.Results/src/TypedResults.cs +++ b/src/Http/Http.Results/src/TypedResults.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Http; public static class TypedResults { /// - /// Creates an that on execution invokes . + /// Creates an that on execution invokes . /// /// The behavior of this method depends on the in use. /// and @@ -29,37 +29,37 @@ public static class TypedResults /// used to perform the authentication /// challenge. /// The authentication schemes to challenge. - /// The created for the response. + /// The created for the response. public static ChallengeHttpResult Challenge( AuthenticationProperties? properties = null, IList? authenticationSchemes = null) => new(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); /// - /// Creates a that on execution invokes . + /// Creates a that on execution invokes . /// /// By default, executing this result returns a . Some authentication schemes, such as cookies, /// will convert to a redirect to show a login page. /// /// - /// used to perform the authentication - /// challenge. - /// The authentication schemes to challenge. - /// The created for the response. /// /// Some authentication schemes, such as cookies, will convert to /// a redirect to show a login page. /// + /// used to perform the authentication + /// challenge. + /// The authentication schemes to challenge. + /// The created for the response. public static ForbidHttpResult Forbid(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) => new(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); /// - /// Creates an that on execution invokes . + /// Creates an that on execution invokes . /// /// The containing the user claims. /// used to perform the sign-in operation. /// The authentication scheme to use for the sign-in operation. - /// The created for the response. + /// The created for the response. public static SignInHttpResult SignIn( ClaimsPrincipal principal, AuthenticationProperties? properties = null, @@ -67,11 +67,11 @@ public static SignInHttpResult SignIn( => new(principal, authenticationScheme, properties); /// - /// Creates an that on execution invokes . + /// Creates an that on execution invokes . /// /// used to perform the sign-out operation. /// The authentication scheme to use for the sign-out operation. - /// The created for the response. + /// The created for the response. public static SignOutHttpResult SignOut(AuthenticationProperties? properties = null, IList? authenticationSchemes = null) => new(authenticationSchemes ?? Array.Empty(), properties); @@ -81,14 +81,14 @@ public static SignOutHttpResult SignOut(AuthenticationProperties? properties = n /// This is an alias for . /// /// - /// The content to write to the response. - /// The content type (MIME type). - /// The content encoding. - /// The created object for the response. /// /// If encoding is provided by both the 'charset' and the parameters, then /// the parameter is chosen as the final encoding. /// + /// The content to write to the response. + /// The content type (MIME type). + /// The content encoding. + /// The created object for the response. public static ContentHttpResult Content(string content, string? contentType = null, Encoding? contentEncoding = null) => Text(content, contentType, contentEncoding); @@ -98,14 +98,14 @@ public static ContentHttpResult Content(string content, string? contentType = nu /// This is an alias for . /// /// - /// The content to write to the response. - /// The content type (MIME type). - /// The content encoding. - /// The created object for the response. /// /// If encoding is provided by both the 'charset' and the parameters, then /// the parameter is chosen as the final encoding. /// + /// The content to write to the response. + /// The content type (MIME type). + /// The content encoding. + /// The created object for the response. public static ContentHttpResult Text(string content, string? contentType = null, Encoding? contentEncoding = null) { MediaTypeHeaderValue? mediaTypeHeaderValue = null; @@ -123,22 +123,22 @@ public static ContentHttpResult Text(string content, string? contentType = null, /// /// The content to write to the response. /// The content type (MIME type). - /// The created object for the response. + /// The created object for the response. public static ContentHttpResult Content(string content, MediaTypeHeaderValue contentType) => new(content, contentType.ToString()); /// - /// Creates a that serializes the specified object to JSON. + /// Creates a that serializes the specified object to JSON. /// + /// Callers should cache an instance of serializer settings to avoid + /// recreating cached data with each call. /// The type of object that will be JSON serialized to the response body. /// The object to write as JSON. /// The serializer options to use when serializing the value. /// The content-type to set on the response. /// The status code to set on the response. - /// The created that serializes the specified + /// The created that serializes the specified /// as JSON format for the response. - /// Callers should cache an instance of serializer settings to avoid - /// recreating cached data with each call. public static JsonHttpResult Json(TValue? data, JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) => new(data, statusCode, options) { @@ -160,7 +160,7 @@ public static JsonHttpResult Json(TValue? data, JsonSerializerOp /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static FileContentHttpResult File( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -193,7 +193,7 @@ public static FileContentHttpResult File( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static FileContentHttpResult Bytes( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -224,7 +224,7 @@ public static FileContentHttpResult Bytes( /// Set to true to enable range requests processing. /// The of when the file was last modified. /// The associated with the file. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static FileContentHttpResult Bytes( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -252,6 +252,9 @@ public static FileContentHttpResult Bytes( /// This API is an alias for . /// /// + /// + /// The parameter is disposed after the response is sent. + /// /// The with the contents of the file. /// The Content-Type of the file. /// The the file name to be used in the Content-Disposition header. @@ -260,10 +263,7 @@ public static FileContentHttpResult Bytes( /// The to be configure the ETag response header /// and perform conditional requests. /// Set to true to enable range requests processing. - /// The created for the response. - /// - /// The parameter is disposed after the response is sent. - /// + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static FileStreamHttpResult File( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -293,6 +293,9 @@ public static FileStreamHttpResult File( /// This API is an alias for . /// /// + /// + /// The parameter is disposed after the response is sent. + /// /// The to write to the response. /// The Content-Type of the response. Defaults to application/octet-stream. /// The the file name to be used in the Content-Disposition header. @@ -301,10 +304,7 @@ public static FileStreamHttpResult File( /// The to be configure the ETag response header /// and perform conditional requests. /// Set to true to enable range requests processing. - /// The created for the response. - /// - /// The parameter is disposed after the response is sent. - /// + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static FileStreamHttpResult Stream( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -331,6 +331,9 @@ public static FileStreamHttpResult Stream( /// if the range is not satisfiable). /// /// + /// + /// The parameter is completed after the response is sent. + /// /// The to write to the response. /// The Content-Type of the response. Defaults to application/octet-stream. /// The the file name to be used in the Content-Disposition header. @@ -339,10 +342,7 @@ public static FileStreamHttpResult Stream( /// The to be configure the ETag response header /// and perform conditional requests. /// Set to true to enable range requests processing. - /// The created for the response. - /// - /// The parameter is completed after the response is sent. - /// + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static FileStreamHttpResult Stream( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -376,7 +376,7 @@ public static FileStreamHttpResult Stream( /// Used to configure the Last-Modified response header and perform conditional range requests. /// The to be configure the ETag response header /// and perform conditional requests. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static PushStreamHttpResult Stream( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -407,7 +407,7 @@ public static PushStreamHttpResult Stream( /// The of when the file was last modified. /// The associated with the file. /// Set to true to enable range requests processing. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static PhysicalFileHttpResult PhysicalFile( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -440,7 +440,7 @@ public static PhysicalFileHttpResult PhysicalFile( /// The of when the file was last modified. /// The associated with the file. /// Set to true to enable range requests processing. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static VirtualFileHttpResult VirtualFile( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -472,7 +472,7 @@ public static VirtualFileHttpResult VirtualFile( /// The URL to redirect to. /// Specifies whether the redirect should be permanent (301) or temporary (302). /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. - /// The created for the response. + /// The created for the response. public static RedirectHttpResult Redirect(string url, bool permanent = false, bool preserveMethod = false) => new(url, permanent, preserveMethod); @@ -488,7 +488,7 @@ public static RedirectHttpResult Redirect(string url, bool permanent = false, bo /// The local URL to redirect to. /// Specifies whether the redirect should be permanent (301) or temporary (302). /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. - /// The created for the response. + /// The created for the response. public static RedirectHttpResult LocalRedirect(string localUrl, bool permanent = false, bool preserveMethod = false) => new(localUrl, acceptLocalUrlOnly: true, permanent, preserveMethod); @@ -506,7 +506,7 @@ public static RedirectHttpResult LocalRedirect(string localUrl, bool permanent = /// Specifies whether the redirect should be permanent (301) or temporary (302). /// If set to true, make the temporary redirect (307) or permanent redirect (308) preserve the initial request method. /// The fragment to add to the URL. - /// The created for the response. + /// The created for the response. public static RedirectToRouteHttpResult RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) => new( routeName: routeName, @@ -526,7 +526,7 @@ public static StatusCodeHttpResult StatusCode(int statusCode) /// /// Produces a response. /// - /// The created for the response. + /// The created for the response. public static NotFound NotFound() => ResultsCache.NotFound; /// @@ -534,19 +534,19 @@ public static StatusCodeHttpResult StatusCode(int statusCode) /// /// The type of object that will be JSON serialized to the response body. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. public static NotFound NotFound(TValue? value) => new(value); /// /// Produces a response. /// - /// The created for the response. + /// The created for the response. public static UnauthorizedHttpResult Unauthorized() => ResultsCache.Unauthorized; /// /// Produces a response. /// - /// The created for the response. + /// The created for the response. public static BadRequest BadRequest() => ResultsCache.BadRequest; /// @@ -554,13 +554,13 @@ public static StatusCodeHttpResult StatusCode(int statusCode) /// /// The type of error object that will be JSON serialized to the response body. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. public static BadRequest BadRequest(TValue? error) => new(error); /// /// Produces a response. /// - /// The created for the response. + /// The created for the response. public static Conflict Conflict() => ResultsCache.Conflict; /// @@ -568,19 +568,19 @@ public static StatusCodeHttpResult StatusCode(int statusCode) /// /// The type of object that will be JSON serialized to the response body. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. public static Conflict Conflict(TValue? error) => new(error); /// /// Produces a response. /// - /// The created for the response. + /// The created for the response. public static NoContent NoContent() => ResultsCache.NoContent; /// /// Produces a response. /// - /// The created for the response. + /// The created for the response. public static Ok Ok() => ResultsCache.Ok; /// @@ -588,13 +588,13 @@ public static StatusCodeHttpResult StatusCode(int statusCode) /// /// The type of object that will be JSON serialized to the response body. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. public static Ok Ok(TValue? value) => new(value); /// /// Produces a response. /// - /// The created for the response. + /// The created for the response. public static UnprocessableEntity UnprocessableEntity() => ResultsCache.UnprocessableEntity; /// @@ -602,7 +602,7 @@ public static StatusCodeHttpResult StatusCode(int statusCode) /// /// The type of object that will be JSON serialized to the response body. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. public static UnprocessableEntity UnprocessableEntity(TValue? error) => new(error); /// @@ -614,7 +614,7 @@ public static StatusCodeHttpResult StatusCode(int statusCode) /// The value for . /// The value for . /// The value for . - /// The created for the response. + /// The created for the response. public static ProblemHttpResult Problem( string? detail = null, string? instance = null, @@ -647,7 +647,7 @@ public static ProblemHttpResult Problem( /// Produces a response. /// /// The object to produce a response from. - /// The created for the response. + /// The created for the response. public static ProblemHttpResult Problem(ProblemDetails problemDetails) { return new(problemDetails); @@ -662,7 +662,7 @@ public static ProblemHttpResult Problem(ProblemDetails problemDetails) /// The value for . Defaults to "One or more validation errors occurred." /// The value for . /// The value for . - /// The created for the response. + /// The created for the response. public static ValidationProblem ValidationProblem( IDictionary errors, string? detail = null, @@ -695,7 +695,7 @@ public static ValidationProblem ValidationProblem( /// Produces a response. /// /// The URI at which the content has been created. - /// The created for the response. + /// The created for the response. public static Created Created(string uri) { if (uri == null) @@ -712,7 +712,7 @@ public static Created Created(string uri) /// The type of object that will be JSON serialized to the response body. /// The URI at which the content has been created. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. public static Created Created(string uri, TValue? value) { if (uri == null) @@ -727,7 +727,7 @@ public static Created Created(string uri, TValue? value) /// Produces a response. /// /// The URI at which the content has been created. - /// The created for the response. + /// The created for the response. public static Created Created(Uri uri) { if (uri == null) @@ -744,7 +744,7 @@ public static Created Created(Uri uri) /// The type of object that will be JSON serialized to the response body. /// The URI at which the content has been created. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. public static Created Created(Uri uri, TValue? value) { if (uri == null) @@ -760,7 +760,7 @@ public static Created Created(Uri uri, TValue? value) /// /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static CreatedAtRoute CreatedAtRoute(string? routeName = null, object? routeValues = null) #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -773,7 +773,7 @@ public static CreatedAtRoute CreatedAtRoute(string? routeName = null, object? ro /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static CreatedAtRoute CreatedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -783,7 +783,7 @@ public static CreatedAtRoute CreatedAtRoute(TValue? value, strin /// Produces a response. /// /// The URI with the location at which the status of requested content can be monitored. - /// The created for the response. + /// The created for the response. public static Accepted Accepted(string? uri) => new(uri); @@ -793,7 +793,7 @@ public static Accepted Accepted(string? uri) /// The type of object that will be JSON serialized to the response body. /// The URI with the location at which the status of requested content can be monitored. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. public static Accepted Accepted(string? uri, TValue? value) => new(uri, value); @@ -801,7 +801,7 @@ public static Accepted Accepted(string? uri, TValue? value) /// Produces a response. /// /// The URI with the location at which the status of requested content can be monitored. - /// The created for the response. + /// The created for the response. public static Accepted Accepted(Uri uri) { if (uri == null) @@ -818,7 +818,7 @@ public static Accepted Accepted(Uri uri) /// The type of object that will be JSON serialized to the response body. /// The URI with the location at which the status of requested content can be monitored. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. public static Accepted Accepted(Uri uri, TValue? value) { if (uri == null) @@ -834,7 +834,7 @@ public static Accepted Accepted(Uri uri, TValue? value) /// /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static AcceptedAtRoute AcceptedAtRoute(string? routeName = null, object? routeValues = null) #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -847,7 +847,7 @@ public static AcceptedAtRoute AcceptedAtRoute(string? routeName = null, object? /// The name of the route to use for generating the URL. /// The route data to use for generating the URL. /// The value to be included in the HTTP response body. - /// The created for the response. + /// The created for the response. #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static AcceptedAtRoute AcceptedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters diff --git a/src/Http/Http.Results/src/ValidationProblem.cs b/src/Http/Http.Results/src/ValidationProblem.cs index 3aebd3fef166..c76b7642f7b0 100644 --- a/src/Http/Http.Results/src/ValidationProblem.cs +++ b/src/Http/Http.Results/src/ValidationProblem.cs @@ -39,6 +39,7 @@ internal ValidationProblem(HttpValidationProblemDetails problemDetails) /// public int StatusCode => StatusCodes.Status400BadRequest; + /// public Task ExecuteAsync(HttpContext httpContext) { var loggerFactory = httpContext.RequestServices.GetRequiredService(); From adba699ed1aaa0f2c01e751845cf9d22717f241c Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Wed, 13 Apr 2022 14:18:29 -0700 Subject: [PATCH 17/35] Fix build errors --- .../Http.Results/src/PublicAPI.Unshipped.txt | 49 ------------------- .../src/UnauthorizedHttpResult.cs | 1 - 2 files changed, 50 deletions(-) diff --git a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt index b5debdbce0e3..8191ee8a973a 100644 --- a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt @@ -195,7 +195,6 @@ Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.FileDownloadName.get Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.FileLength.get -> long? Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.FileName.get -> string! Microsoft.AspNetCore.Http.HttpResults.VirtualFileHttpResult.LastModified.get -> System.DateTimeOffset? -Microsoft.AspNetCore.Http.Results.Typed Microsoft.AspNetCore.Http.TypedResults static Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult.Instance.get -> Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult! static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! @@ -219,54 +218,6 @@ static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! static Microsoft.AspNetCore.Http.HttpResults.ValidationProblem.PopulateMetadata(Microsoft.AspNetCore.Http.Metadata.EndpointMetadataContext! context) -> void -static Microsoft.AspNetCore.Http.Results.Typed.Accepted(System.Uri! uri) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! -static Microsoft.AspNetCore.Http.Results.Typed.Accepted(string! uri) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! -static Microsoft.AspNetCore.Http.Results.Typed.Accepted(System.Uri! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! -static Microsoft.AspNetCore.Http.Results.Typed.Accepted(string! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Accepted! -static Microsoft.AspNetCore.Http.Results.Typed.AcceptedAtRoute(string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute! -static Microsoft.AspNetCore.Http.Results.Typed.AcceptedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.AcceptedAtRoute! -static Microsoft.AspNetCore.Http.Results.Typed.BadRequest() -> Microsoft.AspNetCore.Http.HttpResults.BadRequest! -static Microsoft.AspNetCore.Http.Results.Typed.BadRequest(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.BadRequest! -static Microsoft.AspNetCore.Http.Results.Typed.Bytes(System.ReadOnlyMemory contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.FileContent! -static Microsoft.AspNetCore.Http.Results.Typed.Bytes(byte[]! contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.FileContent! -static Microsoft.AspNetCore.Http.Results.Typed.Challenge(Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, System.Collections.Generic.IList? authenticationSchemes = null) -> Microsoft.AspNetCore.Http.HttpResults.Challenge! -static Microsoft.AspNetCore.Http.Results.Typed.Conflict() -> Microsoft.AspNetCore.Http.HttpResults.Conflict! -static Microsoft.AspNetCore.Http.Results.Typed.Conflict(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.Conflict! -static Microsoft.AspNetCore.Http.Results.Typed.Content(string! content, Microsoft.Net.Http.Headers.MediaTypeHeaderValue! contentType) -> Microsoft.AspNetCore.Http.HttpResults.Content! -static Microsoft.AspNetCore.Http.Results.Typed.Content(string! content, string? contentType = null, System.Text.Encoding? contentEncoding = null) -> Microsoft.AspNetCore.Http.HttpResults.Content! -static Microsoft.AspNetCore.Http.Results.Typed.Created(System.Uri! uri) -> Microsoft.AspNetCore.Http.HttpResults.Created! -static Microsoft.AspNetCore.Http.Results.Typed.Created(string! uri) -> Microsoft.AspNetCore.Http.HttpResults.Created! -static Microsoft.AspNetCore.Http.Results.Typed.Created(System.Uri! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Created! -static Microsoft.AspNetCore.Http.Results.Typed.Created(string! uri, TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Created! -static Microsoft.AspNetCore.Http.Results.Typed.CreatedAtRoute(string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute! -static Microsoft.AspNetCore.Http.Results.Typed.CreatedAtRoute(TValue? value, string? routeName = null, object? routeValues = null) -> Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute! -static Microsoft.AspNetCore.Http.Results.Typed.File(System.IO.Stream! fileStream, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.HttpFileStream! -static Microsoft.AspNetCore.Http.Results.Typed.File(byte[]! fileContents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.FileContent! -static Microsoft.AspNetCore.Http.Results.Typed.Forbid(Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, System.Collections.Generic.IList? authenticationSchemes = null) -> Microsoft.AspNetCore.Http.HttpResults.Forbid! -static Microsoft.AspNetCore.Http.Results.Typed.Json(TValue? data, System.Text.Json.JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null) -> Microsoft.AspNetCore.Http.HttpResults.Json! -static Microsoft.AspNetCore.Http.Results.Typed.LocalRedirect(string! localUrl, bool permanent = false, bool preserveMethod = false) -> Microsoft.AspNetCore.Http.HttpResults.Redirect! -static Microsoft.AspNetCore.Http.Results.Typed.NoContent() -> Microsoft.AspNetCore.Http.HttpResults.NoContent! -static Microsoft.AspNetCore.Http.Results.Typed.NotFound() -> Microsoft.AspNetCore.Http.HttpResults.NotFound! -static Microsoft.AspNetCore.Http.Results.Typed.NotFound(TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.NotFound! -static Microsoft.AspNetCore.Http.Results.Typed.Ok() -> Microsoft.AspNetCore.Http.HttpResults.Ok! -static Microsoft.AspNetCore.Http.Results.Typed.Ok(TValue? value) -> Microsoft.AspNetCore.Http.HttpResults.Ok! -static Microsoft.AspNetCore.Http.Results.Typed.PhysicalFile(string! path, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.PhysicalFile! -static Microsoft.AspNetCore.Http.Results.Typed.Problem(Microsoft.AspNetCore.Mvc.ProblemDetails! problemDetails) -> Microsoft.AspNetCore.Http.HttpResults.Problem! -static Microsoft.AspNetCore.Http.Results.Typed.Problem(string? detail = null, string? instance = null, int? statusCode = null, string? title = null, string? type = null, System.Collections.Generic.IDictionary? extensions = null) -> Microsoft.AspNetCore.Http.HttpResults.Problem! -static Microsoft.AspNetCore.Http.Results.Typed.Redirect(string! url, bool permanent = false, bool preserveMethod = false) -> Microsoft.AspNetCore.Http.HttpResults.Redirect! -static Microsoft.AspNetCore.Http.Results.Typed.RedirectToRoute(string? routeName = null, object? routeValues = null, bool permanent = false, bool preserveMethod = false, string? fragment = null) -> Microsoft.AspNetCore.Http.HttpResults.RedirectToRoute! -static Microsoft.AspNetCore.Http.Results.Typed.SignIn(System.Security.Claims.ClaimsPrincipal! principal, Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, string? authenticationScheme = null) -> Microsoft.AspNetCore.Http.HttpResults.SignIn! -static Microsoft.AspNetCore.Http.Results.Typed.SignOut(Microsoft.AspNetCore.Authentication.AuthenticationProperties? properties = null, System.Collections.Generic.IList? authenticationSchemes = null) -> Microsoft.AspNetCore.Http.HttpResults.SignOut! -static Microsoft.AspNetCore.Http.Results.Typed.StatusCode(int statusCode) -> Microsoft.AspNetCore.Http.HttpResults.Status! -static Microsoft.AspNetCore.Http.Results.Typed.Stream(System.Func! streamWriterCallback, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.HttpResults.PushStream! -static Microsoft.AspNetCore.Http.Results.Typed.Stream(System.IO.Pipelines.PipeReader! pipeReader, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.HttpFileStream! -static Microsoft.AspNetCore.Http.Results.Typed.Stream(System.IO.Stream! stream, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.HttpFileStream! -static Microsoft.AspNetCore.Http.Results.Typed.Text(string! content, string? contentType = null, System.Text.Encoding? contentEncoding = null) -> Microsoft.AspNetCore.Http.HttpResults.Content! -static Microsoft.AspNetCore.Http.Results.Typed.Unauthorized() -> Microsoft.AspNetCore.Http.HttpResults.Unauthorized! -static Microsoft.AspNetCore.Http.Results.Typed.UnprocessableEntity() -> Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity! -static Microsoft.AspNetCore.Http.Results.Typed.UnprocessableEntity(TValue? error) -> Microsoft.AspNetCore.Http.HttpResults.UnprocessableEntity! -static Microsoft.AspNetCore.Http.Results.Typed.ValidationProblem(System.Collections.Generic.IDictionary! errors, string? detail = null, string? instance = null, string? title = null, string? type = null, System.Collections.Generic.IDictionary? extensions = null) -> Microsoft.AspNetCore.Http.HttpResults.BadRequest! -static Microsoft.AspNetCore.Http.Results.Typed.VirtualFile(string! path, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null, bool enableRangeProcessing = false) -> Microsoft.AspNetCore.Http.HttpResults.VirtualFile! static Microsoft.AspNetCore.Http.Results.Bytes(System.ReadOnlyMemory contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.IResult! static Microsoft.AspNetCore.Http.Results.Empty.get -> Microsoft.AspNetCore.Http.IResult! static Microsoft.AspNetCore.Http.Results.Stream(System.Func! streamWriterCallback, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.IResult! diff --git a/src/Http/Http.Results/src/UnauthorizedHttpResult.cs b/src/Http/Http.Results/src/UnauthorizedHttpResult.cs index db04fd1dedfa..fe4b621819b4 100644 --- a/src/Http/Http.Results/src/UnauthorizedHttpResult.cs +++ b/src/Http/Http.Results/src/UnauthorizedHttpResult.cs @@ -4,7 +4,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; - namespace Microsoft.AspNetCore.Http.HttpResults; /// From 14dc834aa3680c522c4e0f20a812034c3b27eb4e Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Wed, 13 Apr 2022 14:56:35 -0700 Subject: [PATCH 18/35] More doc comment fixes --- src/Http/Http.Results/src/Accepted.cs | 2 +- src/Http/Http.Results/src/AcceptedAtRoute.cs | 2 +- src/Http/Http.Results/src/AcceptedAtRouteOfT.cs | 2 +- src/Http/Http.Results/src/AcceptedOfT.cs | 2 +- src/Http/Http.Results/src/BadRequest.cs | 2 +- src/Http/Http.Results/src/BadRequestOfT.cs | 2 +- src/Http/Http.Results/src/Conflict.cs | 2 +- src/Http/Http.Results/src/ConflictOfT.cs | 2 +- src/Http/Http.Results/src/ContentHttpResult.cs | 4 ++-- src/Http/Http.Results/src/Created.cs | 2 +- src/Http/Http.Results/src/CreatedAtRoute.cs | 2 +- src/Http/Http.Results/src/CreatedAtRouteOfT.cs | 2 +- src/Http/Http.Results/src/CreatedOfT.cs | 2 +- src/Http/Http.Results/src/NoContent.cs | 2 +- src/Http/Http.Results/src/NotFound.cs | 2 +- src/Http/Http.Results/src/NotFoundOfT.cs | 2 +- src/Http/Http.Results/src/Ok.cs | 2 +- src/Http/Http.Results/src/OkOfT.cs | 2 +- src/Http/Http.Results/src/ProblemHttpResult.cs | 2 +- src/Http/Http.Results/src/UnauthorizedHttpResult.cs | 2 +- src/Http/Http.Results/src/UnprocessableEntity.cs | 4 +++- src/Http/Http.Results/src/UnprocessableEntityOfT.cs | 8 ++++++-- src/Http/Http.Results/src/ValidationProblem.cs | 4 ++-- 23 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/Http/Http.Results/src/Accepted.cs b/src/Http/Http.Results/src/Accepted.cs index 60961249ab15..fed67811d4dc 100644 --- a/src/Http/Http.Results/src/Accepted.cs +++ b/src/Http/Http.Results/src/Accepted.cs @@ -47,7 +47,7 @@ internal Accepted(Uri locationUri) } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status202Accepted; diff --git a/src/Http/Http.Results/src/AcceptedAtRoute.cs b/src/Http/Http.Results/src/AcceptedAtRoute.cs index e642bbae6eea..96bf99aab6b9 100644 --- a/src/Http/Http.Results/src/AcceptedAtRoute.cs +++ b/src/Http/Http.Results/src/AcceptedAtRoute.cs @@ -50,7 +50,7 @@ internal AcceptedAtRoute( public RouteValueDictionary RouteValues { get; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status202Accepted; diff --git a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs index d440d043f7bd..4855b6e2c89a 100644 --- a/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs @@ -61,7 +61,7 @@ internal AcceptedAtRoute( public RouteValueDictionary RouteValues { get; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status202Accepted; diff --git a/src/Http/Http.Results/src/AcceptedOfT.cs b/src/Http/Http.Results/src/AcceptedOfT.cs index 4cd8c48cddfc..ebe84dbfe6f4 100644 --- a/src/Http/Http.Results/src/AcceptedOfT.cs +++ b/src/Http/Http.Results/src/AcceptedOfT.cs @@ -59,7 +59,7 @@ internal Accepted(Uri locationUri, TValue? value) public TValue? Value { get; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status202Accepted; diff --git a/src/Http/Http.Results/src/BadRequest.cs b/src/Http/Http.Results/src/BadRequest.cs index 01621b2138cf..9dd3b161f111 100644 --- a/src/Http/Http.Results/src/BadRequest.cs +++ b/src/Http/Http.Results/src/BadRequest.cs @@ -22,7 +22,7 @@ internal BadRequest() } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status400BadRequest; diff --git a/src/Http/Http.Results/src/BadRequestOfT.cs b/src/Http/Http.Results/src/BadRequestOfT.cs index 2e044c85afa9..097e3c8793c2 100644 --- a/src/Http/Http.Results/src/BadRequestOfT.cs +++ b/src/Http/Http.Results/src/BadRequestOfT.cs @@ -31,7 +31,7 @@ internal BadRequest(TValue? error) public TValue? Value { get; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status400BadRequest; diff --git a/src/Http/Http.Results/src/Conflict.cs b/src/Http/Http.Results/src/Conflict.cs index 61e7c9f6aa47..12a639bba0e5 100644 --- a/src/Http/Http.Results/src/Conflict.cs +++ b/src/Http/Http.Results/src/Conflict.cs @@ -22,7 +22,7 @@ internal Conflict() } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status409Conflict; diff --git a/src/Http/Http.Results/src/ConflictOfT.cs b/src/Http/Http.Results/src/ConflictOfT.cs index 9c31eae8fd9e..f5fb98e193d6 100644 --- a/src/Http/Http.Results/src/ConflictOfT.cs +++ b/src/Http/Http.Results/src/ConflictOfT.cs @@ -31,7 +31,7 @@ internal Conflict(TValue? error) public TValue? Value { get; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status409Conflict; diff --git a/src/Http/Http.Results/src/ContentHttpResult.cs b/src/Http/Http.Results/src/ContentHttpResult.cs index 8beaf09f01c9..fa765a137ee0 100644 --- a/src/Http/Http.Results/src/ContentHttpResult.cs +++ b/src/Http/Http.Results/src/ContentHttpResult.cs @@ -36,12 +36,12 @@ internal ContentHttpResult(string? content, string? contentType, int? statusCode } /// - /// Gets or set the content representing the body of the response. + /// Gets the content representing the body of the response. /// public string? ResponseContent { get; internal init; } /// - /// Gets or sets the Content-Type header for the response. + /// Gets the Content-Type header for the response. /// public string? ContentType { get; internal init; } diff --git a/src/Http/Http.Results/src/Created.cs b/src/Http/Http.Results/src/Created.cs index 30333e52f5d7..0f94c05771d8 100644 --- a/src/Http/Http.Results/src/Created.cs +++ b/src/Http/Http.Results/src/Created.cs @@ -46,7 +46,7 @@ internal Created(Uri locationUri) } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status201Created; diff --git a/src/Http/Http.Results/src/CreatedAtRoute.cs b/src/Http/Http.Results/src/CreatedAtRoute.cs index 67eb7516eebc..3e7e7fccf4d1 100644 --- a/src/Http/Http.Results/src/CreatedAtRoute.cs +++ b/src/Http/Http.Results/src/CreatedAtRoute.cs @@ -50,7 +50,7 @@ internal CreatedAtRoute( public RouteValueDictionary? RouteValues { get; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status201Created; diff --git a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs index e3240b16032e..de158f722cc0 100644 --- a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs @@ -61,7 +61,7 @@ internal CreatedAtRoute( public RouteValueDictionary? RouteValues { get; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status201Created; diff --git a/src/Http/Http.Results/src/CreatedOfT.cs b/src/Http/Http.Results/src/CreatedOfT.cs index 38b3eed4da7c..5523c5f87a7c 100644 --- a/src/Http/Http.Results/src/CreatedOfT.cs +++ b/src/Http/Http.Results/src/CreatedOfT.cs @@ -59,7 +59,7 @@ internal Created(Uri locationUri, TValue? value) public TValue? Value { get; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status201Created; diff --git a/src/Http/Http.Results/src/NoContent.cs b/src/Http/Http.Results/src/NoContent.cs index 4a718b45f925..68920021f36c 100644 --- a/src/Http/Http.Results/src/NoContent.cs +++ b/src/Http/Http.Results/src/NoContent.cs @@ -21,7 +21,7 @@ internal NoContent() } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status204NoContent; diff --git a/src/Http/Http.Results/src/NotFound.cs b/src/Http/Http.Results/src/NotFound.cs index 2d4ed5876c1f..9b0dbe7848d1 100644 --- a/src/Http/Http.Results/src/NotFound.cs +++ b/src/Http/Http.Results/src/NotFound.cs @@ -21,7 +21,7 @@ internal NotFound() } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status404NotFound; diff --git a/src/Http/Http.Results/src/NotFoundOfT.cs b/src/Http/Http.Results/src/NotFoundOfT.cs index 2516079814d7..8e1bacf533ee 100644 --- a/src/Http/Http.Results/src/NotFoundOfT.cs +++ b/src/Http/Http.Results/src/NotFoundOfT.cs @@ -30,7 +30,7 @@ internal NotFound(TValue? value) public TValue? Value { get; internal init; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status404NotFound; diff --git a/src/Http/Http.Results/src/Ok.cs b/src/Http/Http.Results/src/Ok.cs index f3c6ab9cec50..8d2197d0e458 100644 --- a/src/Http/Http.Results/src/Ok.cs +++ b/src/Http/Http.Results/src/Ok.cs @@ -21,7 +21,7 @@ internal Ok() } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status200OK; diff --git a/src/Http/Http.Results/src/OkOfT.cs b/src/Http/Http.Results/src/OkOfT.cs index c2b8fef133bf..ccbef8a73b79 100644 --- a/src/Http/Http.Results/src/OkOfT.cs +++ b/src/Http/Http.Results/src/OkOfT.cs @@ -30,7 +30,7 @@ internal Ok(TValue? value) public TValue? Value { get; } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status200OK; diff --git a/src/Http/Http.Results/src/ProblemHttpResult.cs b/src/Http/Http.Results/src/ProblemHttpResult.cs index 7837fa4c6927..a0861eaf567b 100644 --- a/src/Http/Http.Results/src/ProblemHttpResult.cs +++ b/src/Http/Http.Results/src/ProblemHttpResult.cs @@ -30,7 +30,7 @@ internal ProblemHttpResult(ProblemDetails problemDetails) public ProblemDetails ProblemDetails { get; } /// - /// Gets the value for the Content-Type header. + /// Gets the value for the Content-Type header: application/problem+json /// public string ContentType => "application/problem+json"; diff --git a/src/Http/Http.Results/src/UnauthorizedHttpResult.cs b/src/Http/Http.Results/src/UnauthorizedHttpResult.cs index fe4b621819b4..e6dfaec3d86f 100644 --- a/src/Http/Http.Results/src/UnauthorizedHttpResult.cs +++ b/src/Http/Http.Results/src/UnauthorizedHttpResult.cs @@ -20,7 +20,7 @@ internal UnauthorizedHttpResult() } /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status401Unauthorized; diff --git a/src/Http/Http.Results/src/UnprocessableEntity.cs b/src/Http/Http.Results/src/UnprocessableEntity.cs index b9884f406596..eaa851ae1c07 100644 --- a/src/Http/Http.Results/src/UnprocessableEntity.cs +++ b/src/Http/Http.Results/src/UnprocessableEntity.cs @@ -21,7 +21,9 @@ internal UnprocessableEntity() { } - /// > + /// + /// Gets the HTTP status code: + /// public int StatusCode => StatusCodes.Status422UnprocessableEntity; /// diff --git a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs index f45a1e6be46f..3232114b569f 100644 --- a/src/Http/Http.Results/src/UnprocessableEntityOfT.cs +++ b/src/Http/Http.Results/src/UnprocessableEntityOfT.cs @@ -25,10 +25,14 @@ internal UnprocessableEntity(TValue? value) HttpResultsHelper.ApplyProblemDetailsDefaultsIfNeeded(Value, StatusCode); } - /// + /// + /// Gets the object result. + /// public TValue? Value { get; } - /// > + /// + /// Gets the HTTP status code: + /// public int StatusCode => StatusCodes.Status422UnprocessableEntity; /// diff --git a/src/Http/Http.Results/src/ValidationProblem.cs b/src/Http/Http.Results/src/ValidationProblem.cs index c76b7642f7b0..af5ee2829707 100644 --- a/src/Http/Http.Results/src/ValidationProblem.cs +++ b/src/Http/Http.Results/src/ValidationProblem.cs @@ -30,12 +30,12 @@ internal ValidationProblem(HttpValidationProblemDetails problemDetails) public HttpValidationProblemDetails ProblemDetails { get; } /// - /// Gets the value for the Content-Type header. + /// Gets the value for the Content-Type header: application/problem+json. /// public string ContentType => "application/problem+json"; /// - /// Gets the HTTP status code. + /// Gets the HTTP status code: /// public int StatusCode => StatusCodes.Status400BadRequest; From c20d4c9dc6d3b1b0164f559c29115505911f9357 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Wed, 13 Apr 2022 14:58:12 -0700 Subject: [PATCH 19/35] Update MinimalSample --- src/Http/samples/MinimalSample/Program.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Http/samples/MinimalSample/Program.cs b/src/Http/samples/MinimalSample/Program.cs index df453dfb596c..12ec6497f3fb 100644 --- a/src/Http/samples/MinimalSample/Program.cs +++ b/src/Http/samples/MinimalSample/Program.cs @@ -31,9 +31,9 @@ app.MapGet("/todo/{id}", Results, NotFound, BadRequest> (int id) => id switch { - <= 0 => Results.Typed.BadRequest(), - >= 1 and <= 10 => Results.Typed.Ok(new Todo(id, "Walk the dog")), - _ => Results.Typed.NotFound() + <= 0 => TypedResults.BadRequest(), + >= 1 and <= 10 => TypedResults.Ok(new Todo(id, "Walk the dog")), + _ => TypedResults.NotFound() }); var extensions = new Dictionary() { { "traceId", "traceId123" } }; @@ -53,7 +53,7 @@ Results.Problem(new HttpValidationProblemDetails(errors) { Status = 400, Extensions = { { "traceId", "traceId123" } } })); app.MapGet("/validation-problem-typed", () => - Results.Typed.ValidationProblem(errors, extensions: extensions)); + TypedResults.ValidationProblem(errors, extensions: extensions)); app.Run(); From cbc2b341809849b99c7561f832d575a7d4a30707 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Wed, 13 Apr 2022 16:35:37 -0700 Subject: [PATCH 20/35] Test that every Results.*** method returns expected IResult type --- .../Http.Results/test/ResultsCacheTests.cs | 2 +- src/Http/Http.Results/test/ResultsTests.cs | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/Http/Http.Results/test/ResultsTests.cs diff --git a/src/Http/Http.Results/test/ResultsCacheTests.cs b/src/Http/Http.Results/test/ResultsCacheTests.cs index f6b7a7ccc98e..6058166f8bc7 100644 --- a/src/Http/Http.Results/test/ResultsCacheTests.cs +++ b/src/Http/Http.Results/test/ResultsCacheTests.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Microsoft.AspNetCore.Http.Results; +namespace Microsoft.AspNetCore.Http.HttpResults; using Mono.TextTemplating; diff --git a/src/Http/Http.Results/test/ResultsTests.cs b/src/Http/Http.Results/test/ResultsTests.cs new file mode 100644 index 000000000000..ccd9e9e94531 --- /dev/null +++ b/src/Http/Http.Results/test/ResultsTests.cs @@ -0,0 +1,87 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq.Expressions; +using System.Reflection; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +public class ResultsTests +{ + [Theory] + [MemberData(nameof(FactoryMethodsFromTuples))] + public void FactoryMethod_ReturnsCorrectResultType(Expression> expression, Type expectedReturnType) + { + var method = expression.Compile(); + Assert.IsType(expectedReturnType, method()); + } + + [Fact] + public void TestTheTests() + { + var testedMethods = new HashSet(FactoryMethodsTuples.Select(t => GetMemberName(t.Item1.Body))); + var actualMethods = new HashSet(typeof(Results).GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(m => !m.IsSpecialName) + .Select(m => m.Name)); + + // Ensure every static method on Results type is covered by at least the default case for its parameters + Assert.All(actualMethods, name => Assert.Single(testedMethods, name)); + } + + private static string GetMemberName(Expression expression) + { + return expression switch + { + MethodCallExpression mce => mce.Method.Name, + MemberExpression me => me.Member.Name, + _ => throw new InvalidOperationException() + }; + } + + private static IEnumerable<(Expression>, Type)> FactoryMethodsTuples { get; } = new List<(Expression>, Type)> + { + (() => Results.Accepted(null, null), typeof(Accepted)), + (() => Results.Accepted(null, new()), typeof(Accepted)), + (() => Results.AcceptedAtRoute("routeName", null, null), typeof(AcceptedAtRoute)), + (() => Results.AcceptedAtRoute("routeName", null, new()), typeof(AcceptedAtRoute)), + (() => Results.BadRequest(null), typeof(BadRequest)), + (() => Results.BadRequest(new()), typeof(BadRequest)), + (() => Results.Bytes(new byte[0], null, null, false, null, null), typeof(FileContentHttpResult)), + (() => Results.Challenge(null, null), typeof(ChallengeHttpResult)), + (() => Results.Conflict(null), typeof(Conflict)), + (() => Results.Conflict(new()), typeof(Conflict)), + (() => Results.Content("content", null, null), typeof(ContentHttpResult)), + (() => Results.Created("/path", null), typeof(Created)), + (() => Results.Created("/path", new()), typeof(Created)), + (() => Results.CreatedAtRoute("routeName", null, null), typeof(CreatedAtRoute)), + (() => Results.CreatedAtRoute("routeName", null, new()), typeof(CreatedAtRoute)), + (() => Results.Empty, typeof(EmptyHttpResult)), + (() => Results.File(new byte[0], null, null, false, null, null), typeof(FileContentHttpResult)), + (() => Results.File(new MemoryStream(), null, null, null, null, false), typeof(FileStreamHttpResult)), + (() => Results.File("C:\\path", null, null, null, null, false), typeof(PhysicalFileHttpResult)), + (() => Results.File("path", null, null, null, null, false), typeof(VirtualFileHttpResult)), + (() => Results.Forbid(null, null), typeof(ForbidHttpResult)), + (() => Results.Json(new(), null, null, null), typeof(JsonHttpResult)), + (() => Results.NoContent(), typeof(NoContent)), + (() => Results.NotFound(null), typeof(NotFound)), + (() => Results.NotFound(new()), typeof(NotFound)), + (() => Results.Ok(null), typeof(Ok)), + (() => Results.Ok(new()), typeof(Ok)), + (() => Results.Problem(new()), typeof(ProblemHttpResult)), + (() => Results.Stream(new MemoryStream(), null, null, null, null, false), typeof(FileStreamHttpResult)), + (() => Results.Stream(s => Task.CompletedTask, null, null, null, null), typeof(PushStreamHttpResult)), + (() => Results.Text("content", null, null), typeof(ContentHttpResult)), + (() => Results.Redirect("/path", false, false), typeof(RedirectHttpResult)), + (() => Results.LocalRedirect("/path", false, false), typeof(RedirectHttpResult)), + (() => Results.RedirectToRoute("routeName", null, false, false, null), typeof(RedirectToRouteHttpResult)), + (() => Results.SignIn(new(), null, null), typeof(SignInHttpResult)), + (() => Results.SignOut(new(), null), typeof(SignOutHttpResult)), + (() => Results.StatusCode(200), typeof(StatusCodeHttpResult)), + (() => Results.Unauthorized(), typeof(UnauthorizedHttpResult)), + (() => Results.UnprocessableEntity(null), typeof(UnprocessableEntity)), + (() => Results.UnprocessableEntity(new()), typeof(UnprocessableEntity)), + (() => Results.ValidationProblem(new Dictionary(), null, null, null, null, null, null), typeof(ProblemHttpResult)) + }; + + public static IEnumerable FactoryMethodsFromTuples() => FactoryMethodsTuples.Select(t => new object[] { t.Item1, t.Item2 }); +} From a6637f1de5471c873f61dbcbff4e70d5bff23457 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Wed, 13 Apr 2022 16:52:55 -0700 Subject: [PATCH 21/35] Added tests for Results.Accepted & Results.AcceptedAtRotue --- src/Http/Http.Results/test/ResultsTests.cs | 88 ++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/Http/Http.Results/test/ResultsTests.cs b/src/Http/Http.Results/test/ResultsTests.cs index ccd9e9e94531..2b023e13c065 100644 --- a/src/Http/Http.Results/test/ResultsTests.cs +++ b/src/Http/Http.Results/test/ResultsTests.cs @@ -3,11 +3,99 @@ using System.Linq.Expressions; using System.Reflection; +using Microsoft.AspNetCore.Routing; namespace Microsoft.AspNetCore.Http.HttpResults; public class ResultsTests { + [Fact] + public void Accepted_WithUrlAndValue_ResultHasCorrectValues() + { + // Arrange + var uri = "https://example.org"; + var value = new { }; + + // Act + var result = Results.Accepted(uri, value) as Accepted; + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(uri, result.Location); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Accepted_WithUrl_ResultHasCorrectValues() + { + // Arrange + var uri = "https://example.org"; + + // Act + var result = Results.Accepted(uri) as Accepted; + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(uri, result.Location); + } + + [Fact] + public void Accepted_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = Results.Accepted() as Accepted; + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Null(result.Location); + } + + [Fact] + public void AcceptedAtRoute_WithRouteNameAndRouteValuesAndValue_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var routeValues = new { foo = 123 }; + var value = new { }; + + // Act + var result = Results.AcceptedAtRoute(routeName, routeValues, value) as AcceptedAtRoute; + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(routeValues), result.RouteValues); + Assert.Equal(value, result.Value); + } + + [Fact] + public void AcceptedAtRoute_WithRouteNameAndRouteValues_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var routeValues = new { foo = 123 }; + + // Act + var result = Results.AcceptedAtRoute(routeName, routeValues) as AcceptedAtRoute; + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(routeValues), result.RouteValues); + } + + [Fact] + public void AcceptedAtRoute_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = Results.AcceptedAtRoute() as AcceptedAtRoute; + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Null(result.RouteName); + Assert.NotNull(result.RouteValues); + } + [Theory] [MemberData(nameof(FactoryMethodsFromTuples))] public void FactoryMethod_ReturnsCorrectResultType(Expression> expression, Type expectedReturnType) From 13a1b658582eceed6ff1c0094f1dd2f6db7422fb Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Wed, 13 Apr 2022 17:06:57 -0700 Subject: [PATCH 22/35] Add more Results tests --- src/Http/Http.Results/test/ResultsTests.cs | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/Http/Http.Results/test/ResultsTests.cs b/src/Http/Http.Results/test/ResultsTests.cs index 2b023e13c065..fb26a0246194 100644 --- a/src/Http/Http.Results/test/ResultsTests.cs +++ b/src/Http/Http.Results/test/ResultsTests.cs @@ -4,6 +4,7 @@ using System.Linq.Expressions; using System.Reflection; using Microsoft.AspNetCore.Routing; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Http.HttpResults; @@ -96,6 +97,53 @@ public void AcceptedAtRoute_WithNoArgs_ResultHasCorrectValues() Assert.NotNull(result.RouteValues); } + [Fact] + public void BadRequest_WithValue_ResultHasCorrectValues() + { + // Arrange + var value = new { }; + + // Act + var result = Results.BadRequest(value) as BadRequest; + + // Assert + Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); + Assert.Equal(value, result.Value); + } + + [Fact] + public void BadRequest_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = Results.BadRequest() as BadRequest; + + // Assert + Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); + } + + [Fact] + public void Bytes_WithRouteNameAndRouteValues_ResultHasCorrectValues() + { + // Arrange + var contents = new byte[0]; + var contentType = "text/plain"; + var fileDownloadName = "testfile"; + var enableRangeProcessing = true; + var lastModified = new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)); + var entityTag = EntityTagHeaderValue.Any; + + // Act + var result = Results.Bytes(contents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag) as FileContentHttpResult; + + // Assert + Assert.Equal(contents, result.FileContents); + Assert.Equal(contentType, result.ContentType); + Assert.Equal(fileDownloadName, result.FileDownloadName); + Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing); + Assert.Equal(lastModified, result.LastModified); + Assert.Equal(entityTag, result.EntityTag); + } + [Theory] [MemberData(nameof(FactoryMethodsFromTuples))] public void FactoryMethod_ReturnsCorrectResultType(Expression> expression, Type expectedReturnType) From 9c81ba7e9249f2e1b1676abf5e978777487c5705 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Thu, 14 Apr 2022 16:23:50 -0700 Subject: [PATCH 23/35] More tests --- src/Http/Http.Results/test/ResultsTests.cs | 170 ++++++++++++++++++++- 1 file changed, 162 insertions(+), 8 deletions(-) diff --git a/src/Http/Http.Results/test/ResultsTests.cs b/src/Http/Http.Results/test/ResultsTests.cs index fb26a0246194..676e2995500e 100644 --- a/src/Http/Http.Results/test/ResultsTests.cs +++ b/src/Http/Http.Results/test/ResultsTests.cs @@ -1,8 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.ObjectModel; using System.Linq.Expressions; using System.Reflection; +using System.Text; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Routing; using Microsoft.Net.Http.Headers; @@ -121,29 +124,180 @@ public void BadRequest_WithNoArgs_ResultHasCorrectValues() Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); } - [Fact] - public void Bytes_WithRouteNameAndRouteValues_ResultHasCorrectValues() + [Theory] + [MemberData(nameof(Bytes_ResultHasCorrectValues_Data))] + public void Bytes_ResultHasCorrectValues(string contentType, string fileDownloadName, bool enableRangeProcessing, DateTimeOffset lastModified, EntityTagHeaderValue entityTag) { // Arrange var contents = new byte[0]; - var contentType = "text/plain"; - var fileDownloadName = "testfile"; - var enableRangeProcessing = true; - var lastModified = new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)); - var entityTag = EntityTagHeaderValue.Any; // Act var result = Results.Bytes(contents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag) as FileContentHttpResult; // Assert Assert.Equal(contents, result.FileContents); - Assert.Equal(contentType, result.ContentType); + Assert.Equal(contentType ?? "application/octet-stream", result.ContentType); Assert.Equal(fileDownloadName, result.FileDownloadName); Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing); Assert.Equal(lastModified, result.LastModified); Assert.Equal(entityTag, result.EntityTag); } + public static IEnumerable Bytes_ResultHasCorrectValues_Data => new List + { + new object[] { "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, + }; + + [Theory] + [MemberData(nameof(Challenge_ResultHasCorrectValues_Data))] + public void Challenge_ResultHasCorrectValues(AuthenticationProperties properties, IList authenticationSchemes) + { + // Act + var result = Results.Challenge(properties, authenticationSchemes) as ChallengeHttpResult; + + // Assert + Assert.Equal(properties, result.Properties); + Assert.Equal(authenticationSchemes ?? new ReadOnlyCollection(new List()), result.AuthenticationSchemes); + } + + public static IEnumerable Challenge_ResultHasCorrectValues_Data => new List + { + new object[] { new AuthenticationProperties(), new List { "TestScheme" } }, + new object[] { new AuthenticationProperties(), default(IList) }, + new object[] { default(AuthenticationProperties), new List { "TestScheme" } }, + new object[] { default(AuthenticationProperties), default(IList) }, + }; + + [Fact] + public void Conflict_WithValue_ResultHasCorrectValues() + { + // Arrange + var value = new { }; + + // Act + var result = Results.Conflict(value) as Conflict; + + // Assert + Assert.Equal(StatusCodes.Status409Conflict, result.StatusCode); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Conflict_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = Results.Conflict() as Conflict; + + // Assert + Assert.Equal(StatusCodes.Status409Conflict, result.StatusCode); + } + + [Fact] + public void Content_WithContentAndMediaType_ResultHasCorrectValues() + { + // Arrange + var content = "test content"; + var mediaType = MediaTypeHeaderValue.Parse("text/plain"); + + // Act + var result = Results.Content(content, mediaType) as ContentHttpResult; + + // Assert + Assert.Null(result.StatusCode); + Assert.Equal(content, result.ResponseContent); + Assert.Equal(mediaType.ToString(), result.ContentType); + } + + [Fact] + public void Content_WithContentAndContentTypeAndEncoding_ResultHasCorrectValues() + { + // Arrange + var content = "test content"; + var contentType = "text/plain"; + var encoding = Encoding.UTF8; + + // Act + var result = Results.Content(content, contentType, null) as ContentHttpResult; + + // Assert + Assert.Null(result.StatusCode); + Assert.Equal(content, result.ResponseContent); + Assert.Equal(contentType, result.ContentType); + } + + [Fact] + public void Created_WithStringUriAndValue_ResultHasCorrectValues() + { + // Arrange + var uri = "https://example.com/entity"; + var value = new { }; + + // Act + var result = Results.Created(uri, value) as Created; + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(uri, result.Location); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Created_WithStringUri_ResultHasCorrectValues() + { + // Arrange + var uri = "https://example.com/entity"; + + // Act + var result = Results.Created(uri, null) as Created; + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(uri, result.Location); + } + + [Fact] + public void Created_WithUriAndValue_ResultHasCorrectValues() + { + // Arrange + var uri = new Uri("https://example.com/entity"); + var value = new { }; + + // Act + var result = Results.Created(uri, value) as Created; + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(uri.ToString(), result.Location); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Created_WithUri_ResultHasCorrectValues() + { + // Arrange + var uri = new Uri("https://example.com/entity"); + + // Act + var result = Results.Created(uri, null) as Created; + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(uri.ToString(), result.Location); + } + + [Fact] + public void Created_WithNullStringUri_ThrowsArgNullException() + { + Assert.Throws("uri", () => Results.Created(default(string), null)); + } + + [Fact] + public void Created_WithNullUri_ThrowsArgNullException() + { + Assert.Throws("uri", () => Results.Created(default(Uri), null)); + } + [Theory] [MemberData(nameof(FactoryMethodsFromTuples))] public void FactoryMethod_ReturnsCorrectResultType(Expression> expression, Type expectedReturnType) From 67a68cffba5a334701e2a3bcafd6367ae21a58f1 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Thu, 14 Apr 2022 16:54:19 -0700 Subject: [PATCH 24/35] More tests --- src/Http/Http.Results/test/ResultsTests.cs | 239 ++++++++++++++++++++- 1 file changed, 233 insertions(+), 6 deletions(-) diff --git a/src/Http/Http.Results/test/ResultsTests.cs b/src/Http/Http.Results/test/ResultsTests.cs index 676e2995500e..1f4e28435c5d 100644 --- a/src/Http/Http.Results/test/ResultsTests.cs +++ b/src/Http/Http.Results/test/ResultsTests.cs @@ -4,7 +4,9 @@ using System.Collections.ObjectModel; using System.Linq.Expressions; using System.Reflection; +using System.Security.Claims; using System.Text; +using System.Text.Json; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Routing; using Microsoft.Net.Http.Headers; @@ -126,13 +128,17 @@ public void BadRequest_WithNoArgs_ResultHasCorrectValues() [Theory] [MemberData(nameof(Bytes_ResultHasCorrectValues_Data))] - public void Bytes_ResultHasCorrectValues(string contentType, string fileDownloadName, bool enableRangeProcessing, DateTimeOffset lastModified, EntityTagHeaderValue entityTag) + public void BytesOrFile_ResultHasCorrectValues(int bytesOrFile, string contentType, string fileDownloadName, bool enableRangeProcessing, DateTimeOffset lastModified, EntityTagHeaderValue entityTag) { // Arrange var contents = new byte[0]; // Act - var result = Results.Bytes(contents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag) as FileContentHttpResult; + var result = bytesOrFile switch + { + 0 => Results.Bytes(contents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag), + _ => Results.File(contents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag) + } as FileContentHttpResult; // Assert Assert.Equal(contents, result.FileContents); @@ -145,12 +151,14 @@ public void Bytes_ResultHasCorrectValues(string contentType, string fileDownload public static IEnumerable Bytes_ResultHasCorrectValues_Data => new List { - new object[] { "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, - new object[] { default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, + new object[] { 0, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 0, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, + new object[] { 1, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 1, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, }; [Theory] - [MemberData(nameof(Challenge_ResultHasCorrectValues_Data))] + [MemberData(nameof(ChallengeForbidSignInOut_ResultHasCorrectValues_Data))] public void Challenge_ResultHasCorrectValues(AuthenticationProperties properties, IList authenticationSchemes) { // Act @@ -161,7 +169,47 @@ public void Challenge_ResultHasCorrectValues(AuthenticationProperties properties Assert.Equal(authenticationSchemes ?? new ReadOnlyCollection(new List()), result.AuthenticationSchemes); } - public static IEnumerable Challenge_ResultHasCorrectValues_Data => new List + [Theory] + [MemberData(nameof(ChallengeForbidSignInOut_ResultHasCorrectValues_Data))] + public void Forbid_ResultHasCorrectValues(AuthenticationProperties properties, IList authenticationSchemes) + { + // Act + var result = Results.Forbid(properties, authenticationSchemes) as ForbidHttpResult; + + // Assert + Assert.Equal(properties, result.Properties); + Assert.Equal(authenticationSchemes ?? new ReadOnlyCollection(new List()), result.AuthenticationSchemes); + } + + [Theory] + [MemberData(nameof(ChallengeForbidSignInOut_ResultHasCorrectValues_Data))] + public void SignOut_ResultHasCorrectValues(AuthenticationProperties properties, IList authenticationSchemes) + { + // Act + var result = Results.SignOut(properties, authenticationSchemes) as SignOutHttpResult; + + // Assert + Assert.Equal(properties, result.Properties); + Assert.Equal(authenticationSchemes ?? new ReadOnlyCollection(new List()), result.AuthenticationSchemes); + } + + [Theory] + [MemberData(nameof(ChallengeForbidSignInOut_ResultHasCorrectValues_Data))] + public void SignIn_ResultHasCorrectValues(AuthenticationProperties properties, IList authenticationSchemes) + { + // Arrange + var principal = new ClaimsPrincipal(); + + // Act + var result = Results.SignIn(principal, properties, authenticationSchemes?.First()) as SignInHttpResult; + + // Assert + Assert.Equal(principal, result.Principal); + Assert.Equal(properties, result.Properties); + Assert.Equal(authenticationSchemes?.First(), result.AuthenticationScheme); + } + + public static IEnumerable ChallengeForbidSignInOut_ResultHasCorrectValues_Data => new List { new object[] { new AuthenticationProperties(), new List { "TestScheme" } }, new object[] { new AuthenticationProperties(), default(IList) }, @@ -169,6 +217,12 @@ public void Challenge_ResultHasCorrectValues(AuthenticationProperties properties new object[] { default(AuthenticationProperties), default(IList) }, }; + [Fact] + public void SignIn_WithNullPrincipal_ThrowsArgNullException() + { + Assert.Throws("principal", () => Results.SignIn(null)); + } + [Fact] public void Conflict_WithValue_ResultHasCorrectValues() { @@ -298,6 +352,179 @@ public void Created_WithNullUri_ThrowsArgNullException() Assert.Throws("uri", () => Results.Created(default(Uri), null)); } + [Fact] + public void CreatedAtRoute_WithRouteNameAndRouteValuesAndValue_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var routeValues = new { foo = 123 }; + var value = new { }; + + // Act + var result = Results.CreatedAtRoute(routeName, routeValues, value) as CreatedAtRoute; + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(routeValues), result.RouteValues); + Assert.Equal(value, result.Value); + } + + [Fact] + public void CreatedAtRoute_WithRouteNameAndValue_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var value = new { }; + + // Act + var result = Results.CreatedAtRoute(routeName, null, value) as CreatedAtRoute; + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(), result.RouteValues); + Assert.Equal(value, result.Value); + } + + [Fact] + public void CreatedAtRoute_WithRouteName_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + + // Act + var result = Results.CreatedAtRoute(routeName, null, null) as CreatedAtRoute; + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(), result.RouteValues); + } + + [Fact] + public void CreatedAtRoute_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = Results.CreatedAtRoute() as CreatedAtRoute; + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Null(result.RouteName); + Assert.Equal(new RouteValueDictionary(), result.RouteValues); + } + + [Fact] + public void Empty_IsEmptyInstance() + { + // Act + var result = Results.Empty as EmptyHttpResult; + + // Assert + Assert.Equal(EmptyHttpResult.Instance, result); + } + + [Fact] + public void Json_WithAllArgs_ResultHasCorrectValues() + { + // Arrange + var data = new { }; + var options = new JsonSerializerOptions(); + var contentType = "application/custom+json"; + var statusCode = StatusCodes.Status208AlreadyReported; + + // Act + var result = Results.Json(data, options, contentType, statusCode) as JsonHttpResult; + + // Assert + Assert.Equal(data, result.Value); + Assert.Equal(options, result.JsonSerializerOptions); + Assert.Equal(contentType, result.ContentType); + Assert.Equal(statusCode, result.StatusCode); + } + + [Fact] + public void Json_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = Results.Json(null) as JsonHttpResult; + + // Assert + Assert.Null(result.Value); + Assert.Null(result.JsonSerializerOptions); + Assert.Null(result.ContentType); + Assert.Null(result.StatusCode); + } + + [Fact] + public void LocalRedirect_WithUrl_ResultHasCorrectValues() + { + // Arrange + var localUrl = "test/path"; + + // Act + var result = Results.LocalRedirect(localUrl) as RedirectHttpResult; + + // Assert + Assert.Equal(localUrl, result.Url); + Assert.True(result.AcceptLocalUrlOnly); + Assert.False(result.Permanent); + Assert.False(result.PreserveMethod); + } + + [Fact] + public void LocalRedirect_WithUrlAndPermanentTrue_ResultHasCorrectValues() + { + // Arrange + var localUrl = "test/path"; + var permanent = true; + + // Act + var result = Results.LocalRedirect(localUrl, permanent) as RedirectHttpResult; + + // Assert + Assert.Equal(localUrl, result.Url); + Assert.True(result.AcceptLocalUrlOnly); + Assert.True(result.Permanent); + Assert.False(result.PreserveMethod); + } + + [Fact] + public void LocalRedirect_WithUrlAndPermanentTrueAndPreserveTrue_ResultHasCorrectValues() + { + // Arrange + var localUrl = "test/path"; + var permanent = true; + var preserveMethod = true; + + // Act + var result = Results.LocalRedirect(localUrl, permanent, preserveMethod) as RedirectHttpResult; + + // Assert + Assert.Equal(localUrl, result.Url); + Assert.True(result.AcceptLocalUrlOnly); + Assert.True(result.Permanent); + Assert.True(result.PreserveMethod); + } + + [Fact] + public void LocalRedirect_WithNonLocalUrlAndPermanentTrueAndPreserveTrue_ResultHasCorrectValues() + { + // Arrange + var localUrl = "https://example.com/non-local-url/example"; + var permanent = true; + var preserveMethod = true; + + // Act + var result = Results.LocalRedirect(localUrl, permanent, preserveMethod) as RedirectHttpResult; + + // Assert + Assert.Equal(localUrl, result.Url); + Assert.True(result.AcceptLocalUrlOnly); + Assert.True(result.Permanent); + Assert.True(result.PreserveMethod); + } + [Theory] [MemberData(nameof(FactoryMethodsFromTuples))] public void FactoryMethod_ReturnsCorrectResultType(Expression> expression, Type expectedReturnType) From dad3b438c6d1ab53ce45da65ccff68cd31e4523d Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Thu, 14 Apr 2022 17:09:05 -0700 Subject: [PATCH 25/35] More tests --- src/Http/Http.Results/test/ResultsTests.cs | 131 +++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/src/Http/Http.Results/test/ResultsTests.cs b/src/Http/Http.Results/test/ResultsTests.cs index 1f4e28435c5d..8ebfd7206a0c 100644 --- a/src/Http/Http.Results/test/ResultsTests.cs +++ b/src/Http/Http.Results/test/ResultsTests.cs @@ -8,6 +8,7 @@ using System.Text; using System.Text.Json; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.Net.Http.Headers; @@ -525,6 +526,136 @@ public void LocalRedirect_WithNonLocalUrlAndPermanentTrueAndPreserveTrue_ResultH Assert.True(result.PreserveMethod); } + [Fact] + public void NoContent_ResultHasCorrectValues() + { + // Act + var result = Results.NoContent() as NoContent; + + // Assert + Assert.Equal(StatusCodes.Status204NoContent, result.StatusCode); + } + + [Fact] + public void NotFound_WithValue_ResultHasCorrectValues() + { + // Arrange + var value = new { }; + + // Act + var result = Results.NotFound(value) as NotFound; + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, result.StatusCode); + Assert.Equal(value, result.Value); + } + + [Fact] + public void NotFound_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = Results.NotFound() as NotFound; + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, result.StatusCode); + } + + [Fact] + public void Ok_WithValue_ResultHasCorrectValues() + { + // Arrange + var value = new { }; + + // Act + var result = Results.Ok(value) as Ok; + + // Assert + Assert.Equal(StatusCodes.Status200OK, result.StatusCode); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Ok_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = Results.Ok() as Ok; + + // Assert + Assert.Equal(StatusCodes.Status200OK, result.StatusCode); + } + + [Fact] + public void Problem_WithArgs_ResultHasCorrectValues() + { + // Arrange + var detail = "test detail"; + var instance = "test instance"; + var statusCode = StatusCodes.Status409Conflict; + var title = "test title"; + var type = "test type"; + var extensions = new Dictionary { { "test", "value" } }; + + // Act + var result = Results.Problem(detail, instance, statusCode, title, type, extensions) as ProblemHttpResult; + + // Assert + Assert.Equal(detail, result.ProblemDetails.Detail); + Assert.Equal(instance, result.ProblemDetails.Instance); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(statusCode, result.StatusCode); + Assert.Equal(title, result.ProblemDetails.Title); + Assert.Equal(type, result.ProblemDetails.Type); + Assert.Equal(extensions, result.ProblemDetails.Extensions); + } + + [Fact] + public void Problem_WithNoArgs_ResultHasCorrectValues() + { + /// Act + var result = Results.Problem() as ProblemHttpResult; + + // Assert + Assert.Null(result.ProblemDetails.Detail); + Assert.Null(result.ProblemDetails.Instance); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(StatusCodes.Status500InternalServerError, result.StatusCode); + Assert.Equal("An error occurred while processing your request.", result.ProblemDetails.Title); + Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.6.1", result.ProblemDetails.Type); + Assert.Empty(result.ProblemDetails.Extensions); + } + + [Fact] + public void Problem_WithProblemArg_ResultHasCorrectValues() + { + // Arrange + var problem = new ProblemDetails { Title = "Test title" }; + + // Act + var result = Results.Problem(problem) as ProblemHttpResult; + + // Assert + Assert.Equal(problem, result.ProblemDetails); + Assert.Equal("Test title", result.ProblemDetails.Title); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(StatusCodes.Status500InternalServerError, result.StatusCode); + } + + [Fact] + public void Problem_WithValidationProblemArg_ResultHasCorrectValues() + { + // Arrange + var problem = new HttpValidationProblemDetails { Title = "Test title" }; + + // Act + var result = Results.Problem(problem) as ProblemHttpResult; + + // Assert + Assert.Equal(problem, result.ProblemDetails); + Assert.Equal("Test title", result.ProblemDetails.Title); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); + } + [Theory] [MemberData(nameof(FactoryMethodsFromTuples))] public void FactoryMethod_ReturnsCorrectResultType(Expression> expression, Type expectedReturnType) From 3aa81b852ef4bf353aa1807e0ac896ec790a9602 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 15 Apr 2022 13:43:07 -0700 Subject: [PATCH 26/35] Add tests for result types implementing IEndpointMetadataProvider --- .../test/AcceptedAtRouteOfTResultTests.cs | 25 +++++++++++++++++++ .../test/AcceptedAtRouteResultTests.cs | 21 ++++++++++++++++ .../test/AcceptedOfTResultTests.cs | 25 +++++++++++++++++++ .../Http.Results/test/AcceptedResultTests.cs | 20 +++++++++++++++ .../test/BadRequestOfTResultTests.cs | 25 +++++++++++++++++++ .../test/BadRequestResultTests.cs | 21 ++++++++++++++++ .../test/ConflictOfTResultTests.cs | 25 +++++++++++++++++++ .../Http.Results/test/ConflictResultTests.cs | 21 ++++++++++++++++ .../test/CreatedAtRouteOfTResultTests.cs | 25 +++++++++++++++++++ .../test/CreatedAtRouteResultTests.cs | 21 ++++++++++++++++ .../test/CreatedOfTResultTests.cs | 25 +++++++++++++++++++ .../Http.Results/test/CreatedResultTests.cs | 21 ++++++++++++++++ .../Http.Results/test/NoContentResultTests.cs | 21 ++++++++++++++++ .../test/NotFoundOfTResultTests.cs | 25 +++++++++++++++++++ .../Http.Results/test/NotFoundResultTests.cs | 21 ++++++++++++++++ .../Http.Results/test/OkOfTResultTests.cs | 25 +++++++++++++++++++ src/Http/Http.Results/test/OkResultTests.cs | 21 ++++++++++++++++ .../test/UnprocessableEntityOfTResultTests.cs | 25 +++++++++++++++++++ .../test/UnprocessableEntityResultTests.cs | 21 ++++++++++++++++ 19 files changed, 434 insertions(+) diff --git a/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs b/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs index efca3f97e17d..45fb26fd95f1 100644 --- a/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs +++ b/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; @@ -114,6 +116,29 @@ await ExceptionAssert.ThrowsAsync(() => "No route matches the supplied values."); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + AcceptedAtRoute MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata>(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status202Accepted, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private record Todo(int Id, string Title); + private static HttpContext GetHttpContext(LinkGenerator linkGenerator) { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs b/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs index 3bc4ea61530d..4c43df6dfb70 100644 --- a/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs +++ b/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; @@ -67,6 +69,25 @@ await ExceptionAssert.ThrowsAsync(() => "No route matches the supplied values."); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + AcceptedAtRoute MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status202Accepted, producesResponseTypeMetadata.StatusCode); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static HttpContext GetHttpContext(LinkGenerator linkGenerator) { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/AcceptedOfTResultTests.cs b/src/Http/Http.Results/test/AcceptedOfTResultTests.cs index 9ad9dcdabdef..3bc477cffad1 100644 --- a/src/Http/Http.Results/test/AcceptedOfTResultTests.cs +++ b/src/Http/Http.Results/test/AcceptedOfTResultTests.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Http.HttpResults; @@ -54,6 +56,29 @@ public void AcceptedResult_ProblemDetails_SetsStatusCodeAndValue() Assert.Equal(obj, result.Value); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + Accepted MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata>(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status202Accepted, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private record Todo(int Id, string Title); + private static HttpContext GetHttpContext() { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/AcceptedResultTests.cs b/src/Http/Http.Results/test/AcceptedResultTests.cs index 8d5bd2d3499a..a8fad797f1ea 100644 --- a/src/Http/Http.Results/test/AcceptedResultTests.cs +++ b/src/Http/Http.Results/test/AcceptedResultTests.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Http.HttpResults; @@ -24,6 +26,24 @@ public async Task ExecuteResultAsync_SetsStatusCodeAndLocationHeader() Assert.Equal(expectedUrl, httpContext.Response.Headers["Location"]); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + Accepted MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + Assert.Contains(context.EndpointMetadata, m => m is ProducesResponseTypeMetadata { StatusCode: StatusCodes.Status202Accepted }); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static HttpContext GetHttpContext() { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/BadRequestOfTResultTests.cs b/src/Http/Http.Results/test/BadRequestOfTResultTests.cs index ef0b6b088ce6..8d223c3b4681 100644 --- a/src/Http/Http.Results/test/BadRequestOfTResultTests.cs +++ b/src/Http/Http.Results/test/BadRequestOfTResultTests.cs @@ -3,7 +3,9 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -96,6 +98,29 @@ public async Task BadRequestObjectResult_ExecuteResultAsync_UsesStatusCodeFromRe Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + BadRequest MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata>(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status400BadRequest, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private record Todo(int Id, string Title); + private static IServiceProvider CreateServices() { var services = new ServiceCollection(); diff --git a/src/Http/Http.Results/test/BadRequestResultTests.cs b/src/Http/Http.Results/test/BadRequestResultTests.cs index 7d181ab45e35..f6078d5a8303 100644 --- a/src/Http/Http.Results/test/BadRequestResultTests.cs +++ b/src/Http/Http.Results/test/BadRequestResultTests.cs @@ -3,7 +3,9 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -37,6 +39,25 @@ public async Task BadRequestObjectResult_ExecuteAsync_SetsStatusCode() Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + BadRequest MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status400BadRequest, producesResponseTypeMetadata.StatusCode); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static IServiceProvider CreateServices() { var services = new ServiceCollection(); diff --git a/src/Http/Http.Results/test/ConflictOfTResultTests.cs b/src/Http/Http.Results/test/ConflictOfTResultTests.cs index 7fa3387520a4..9ecf5b06dcb0 100644 --- a/src/Http/Http.Results/test/ConflictOfTResultTests.cs +++ b/src/Http/Http.Results/test/ConflictOfTResultTests.cs @@ -3,7 +3,9 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -75,6 +77,29 @@ public async Task ConflictObjectResult_ExecuteResultAsync_FormatsData() Assert.Equal("\"Hello\"", Encoding.UTF8.GetString(stream.ToArray())); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + Conflict MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata>(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status409Conflict, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private record Todo(int Id, string Title); + private static IServiceProvider CreateServices() { var services = new ServiceCollection(); diff --git a/src/Http/Http.Results/test/ConflictResultTests.cs b/src/Http/Http.Results/test/ConflictResultTests.cs index 8b1420c23a29..45337e675be0 100644 --- a/src/Http/Http.Results/test/ConflictResultTests.cs +++ b/src/Http/Http.Results/test/ConflictResultTests.cs @@ -3,7 +3,9 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -38,6 +40,25 @@ public async Task ConflictObjectResult_ExecuteAsync_SetsStatusCode() Assert.Equal(StatusCodes.Status409Conflict, httpContext.Response.StatusCode); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + Conflict MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status409Conflict, producesResponseTypeMetadata.StatusCode); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static IServiceProvider CreateServices() { var services = new ServiceCollection(); diff --git a/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs b/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs index d1432d00dec9..afa6c0cfb4d6 100644 --- a/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs +++ b/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; @@ -81,6 +83,29 @@ await ExceptionAssert.ThrowsAsync( "No route matches the supplied values."); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + CreatedAtRoute MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata>(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status201Created, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private record Todo(int Id, string Title); + private static HttpContext GetHttpContext(string expectedUrl) { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs b/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs index 292ee76ef924..bd8f0c2a0fb9 100644 --- a/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs +++ b/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; @@ -63,6 +65,25 @@ await ExceptionAssert.ThrowsAsync( "No route matches the supplied values."); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + CreatedAtRoute MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status201Created, producesResponseTypeMetadata.StatusCode); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static HttpContext GetHttpContext(string expectedUrl) { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/CreatedOfTResultTests.cs b/src/Http/Http.Results/test/CreatedOfTResultTests.cs index fa3c8ff372e4..f0ac3d838ffc 100644 --- a/src/Http/Http.Results/test/CreatedOfTResultTests.cs +++ b/src/Http/Http.Results/test/CreatedOfTResultTests.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -89,6 +91,29 @@ public async Task CreatedResult_ExecuteResultAsync_FormatsData() Assert.Equal("\"testInput\"", response); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + Created MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata>(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status201Created, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private record Todo(int Id, string Title); + private static HttpContext GetHttpContext() { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/CreatedResultTests.cs b/src/Http/Http.Results/test/CreatedResultTests.cs index 6feb00dab671..0591cd7db003 100644 --- a/src/Http/Http.Results/test/CreatedResultTests.cs +++ b/src/Http/Http.Results/test/CreatedResultTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -55,6 +57,25 @@ public async Task CreatedResult_OverwritesLocationHeader() Assert.Equal(location, httpContext.Response.Headers["Location"]); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + Created MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status201Created, producesResponseTypeMetadata.StatusCode); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static HttpContext GetHttpContext() { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/NoContentResultTests.cs b/src/Http/Http.Results/test/NoContentResultTests.cs index 10c33f198771..de0c82a63277 100644 --- a/src/Http/Http.Results/test/NoContentResultTests.cs +++ b/src/Http/Http.Results/test/NoContentResultTests.cs @@ -3,6 +3,8 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using System.Reflection; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -34,6 +36,25 @@ public void NoContentResultTests_ExecuteResultSetsResponseStatusCode() Assert.Equal(StatusCodes.Status204NoContent, httpContext.Response.StatusCode); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + NoContent MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status204NoContent, producesResponseTypeMetadata.StatusCode); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static IServiceCollection CreateServices() { var services = new ServiceCollection(); diff --git a/src/Http/Http.Results/test/NotFoundOfTResultTests.cs b/src/Http/Http.Results/test/NotFoundOfTResultTests.cs index 90b5d34590d7..9a15ae0d76c7 100644 --- a/src/Http/Http.Results/test/NotFoundOfTResultTests.cs +++ b/src/Http/Http.Results/test/NotFoundOfTResultTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -57,6 +59,29 @@ public async Task NotFoundObjectResult_ExecuteSuccessful() Assert.Equal(StatusCodes.Status404NotFound, httpContext.Response.StatusCode); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + NotFound MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata>(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status404NotFound, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private record Todo(int Id, string Title); + private static HttpContext GetHttpContext() { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/NotFoundResultTests.cs b/src/Http/Http.Results/test/NotFoundResultTests.cs index e61a0b78b858..20d69a54e488 100644 --- a/src/Http/Http.Results/test/NotFoundResultTests.cs +++ b/src/Http/Http.Results/test/NotFoundResultTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -33,6 +35,25 @@ public async Task NotFoundObjectResult_ExecuteSuccessful() Assert.Equal(StatusCodes.Status404NotFound, httpContext.Response.StatusCode); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + NotFound MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status404NotFound, producesResponseTypeMetadata.StatusCode); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static HttpContext GetHttpContext() { var httpContext = new DefaultHttpContext(); diff --git a/src/Http/Http.Results/test/OkOfTResultTests.cs b/src/Http/Http.Results/test/OkOfTResultTests.cs index 157316008eeb..11e1af79a23e 100644 --- a/src/Http/Http.Results/test/OkOfTResultTests.cs +++ b/src/Http/Http.Results/test/OkOfTResultTests.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -74,6 +76,29 @@ public async Task OkObjectResult_ExecuteAsync_SetsStatusCode() Assert.Equal(StatusCodes.Status200OK, httpContext.Response.StatusCode); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + Ok MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata>(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status200OK, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private record Todo(int Id, string Title); + private static IServiceProvider CreateServices() { var services = new ServiceCollection(); diff --git a/src/Http/Http.Results/test/OkResultTests.cs b/src/Http/Http.Results/test/OkResultTests.cs index 37cfd1a52b8d..c199a2b08634 100644 --- a/src/Http/Http.Results/test/OkResultTests.cs +++ b/src/Http/Http.Results/test/OkResultTests.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -37,6 +39,25 @@ public async Task OkObjectResult_ExecuteAsync_SetsStatusCode() Assert.Equal(StatusCodes.Status200OK, httpContext.Response.StatusCode); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + Ok MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status200OK, producesResponseTypeMetadata.StatusCode); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static IServiceProvider CreateServices() { var services = new ServiceCollection(); diff --git a/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs b/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs index 5003c83b6ff7..d5d3938d85a2 100644 --- a/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs +++ b/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs @@ -3,7 +3,9 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -74,6 +76,29 @@ public async Task UnprocessableEntityObjectResult_ExecuteResultAsync_FormatsData Assert.Equal("\"Hello\"", Encoding.UTF8.GetString(stream.ToArray())); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + UnprocessableEntity MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata>(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status422UnprocessableEntity, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private record Todo(int Id, string Title); + private static IServiceProvider CreateServices() { var services = new ServiceCollection(); diff --git a/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs b/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs index 44075ada9574..049d3bfab56f 100644 --- a/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs +++ b/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs @@ -3,7 +3,9 @@ namespace Microsoft.AspNetCore.Http.HttpResults; +using System.Reflection; using System.Text; +using Microsoft.AspNetCore.Http.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -37,6 +39,25 @@ public async Task UnprocessableEntityObjectResult_ExecuteAsync_SetsStatusCode() Assert.Equal(StatusCodes.Status422UnprocessableEntity, httpContext.Response.StatusCode); } + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + UnprocessableEntity MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status422UnprocessableEntity, producesResponseTypeMetadata.StatusCode); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + private static IServiceProvider CreateServices() { var services = new ServiceCollection(); From fda085c52a745772d589ac60512e9832622ec612 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 15 Apr 2022 15:37:34 -0700 Subject: [PATCH 27/35] Added ValidationProblem tests --- .../Http.Results/src/ValidationProblem.cs | 11 +-- .../test/ValidationProblemResultTests.cs | 88 +++++++++++++++++++ 2 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 src/Http/Http.Results/test/ValidationProblemResultTests.cs diff --git a/src/Http/Http.Results/src/ValidationProblem.cs b/src/Http/Http.Results/src/ValidationProblem.cs index af5ee2829707..f0f06ef575e4 100644 --- a/src/Http/Http.Results/src/ValidationProblem.cs +++ b/src/Http/Http.Results/src/ValidationProblem.cs @@ -13,13 +13,14 @@ namespace Microsoft.AspNetCore.Http.HttpResults; /// public sealed class ValidationProblem : IResult, IEndpointMetadataProvider { - /// - /// Creates a new instance with - /// the provided . - /// - /// The instance to format in the entity body. internal ValidationProblem(HttpValidationProblemDetails problemDetails) { + ArgumentNullException.ThrowIfNull(problemDetails, nameof(problemDetails)); + if (problemDetails is { Status: not null and not StatusCodes.Status400BadRequest }) + { + throw new ArgumentException($"{nameof(ValidationProblem)} only supports a 400 Bad Request response status code.", nameof(problemDetails)); + } + ProblemDetails = problemDetails; HttpResultsHelper.ApplyProblemDetailsDefaults(ProblemDetails, statusCode: StatusCodes.Status400BadRequest); } diff --git a/src/Http/Http.Results/test/ValidationProblemResultTests.cs b/src/Http/Http.Results/test/ValidationProblemResultTests.cs new file mode 100644 index 000000000000..e6b9455d43ef --- /dev/null +++ b/src/Http/Http.Results/test/ValidationProblemResultTests.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; +using System.Text.Json; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Http.Metadata; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +public class ValidationProblemResultTests +{ + [Fact] + public async Task ExecuteAsync_UsesDefaults_ForProblemDetails() + { + // Arrange + var details = new HttpValidationProblemDetails(); + var result = new ValidationProblem(details); + var stream = new MemoryStream(); + var httpContext = new DefaultHttpContext + { + RequestServices = CreateServices(), + Response = + { + Body = stream, + }, + }; + + // Act + await result.ExecuteAsync(httpContext); + + // Assert + Assert.Equal(StatusCodes.Status400BadRequest, httpContext.Response.StatusCode); + Assert.Equal(details, result.ProblemDetails); + stream.Position = 0; + var responseDetails = JsonSerializer.Deserialize(stream); + Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.5.1", responseDetails.Type); + Assert.Equal("One or more validation errors occurred.", responseDetails.Title); + Assert.Equal(StatusCodes.Status400BadRequest, responseDetails.Status); + } + + [Fact] + public void ExecuteAsync_ThrowsArgumentNullException_ForNullProblemDetails() + { + Assert.Throws("problemDetails", () => new ValidationProblem(null)); + } + + [Fact] + public void ExecuteAsync_ThrowsArgumentException_ForNon400StatusCodeFromProblemDetails() + { + Assert.Throws("problemDetails", () => new ValidationProblem( + new HttpValidationProblemDetails { Status = StatusCodes.Status413RequestEntityTooLarge, })); + } + + [Fact] + public void PopulateMetadata_AddsResponseTypeMetadata() + { + // Arrange + ValidationProblem MyApi() { throw new NotImplementedException(); } + var metadata = new List(); + var context = new EndpointMetadataContext(((Delegate)MyApi).GetMethodInfo(), metadata, null); + + // Act + PopulateMetadata(context); + + // Assert + var producesResponseTypeMetadata = context.EndpointMetadata.OfType().Last(); + Assert.Equal(StatusCodes.Status400BadRequest, producesResponseTypeMetadata.StatusCode); + Assert.Equal(typeof(HttpValidationProblemDetails), producesResponseTypeMetadata.Type); + Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/problem+json"); + } + + private static void PopulateMetadata(EndpointMetadataContext context) + where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(context); + + private static IServiceProvider CreateServices() + { + var services = new ServiceCollection(); + services.AddTransient(typeof(ILogger<>), typeof(NullLogger<>)); + services.AddSingleton(NullLoggerFactory.Instance); + + return services.BuildServiceProvider(); + } +} From b9b5dd350b32968d73eb203430f58a8ac769749c Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 15 Apr 2022 17:43:59 -0700 Subject: [PATCH 28/35] Add more results tests --- src/Http/Http.Results/test/ResultsTests.cs | 216 ++++++++++++++++++++- 1 file changed, 214 insertions(+), 2 deletions(-) diff --git a/src/Http/Http.Results/test/ResultsTests.cs b/src/Http/Http.Results/test/ResultsTests.cs index 8ebfd7206a0c..4530c9babb2e 100644 --- a/src/Http/Http.Results/test/ResultsTests.cs +++ b/src/Http/Http.Results/test/ResultsTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.ObjectModel; +using System.IO.Pipelines; using System.Linq.Expressions; using System.Reflection; using System.Security.Claims; @@ -128,7 +129,7 @@ public void BadRequest_WithNoArgs_ResultHasCorrectValues() } [Theory] - [MemberData(nameof(Bytes_ResultHasCorrectValues_Data))] + [MemberData(nameof(BytesOrFile_ResultHasCorrectValues_Data))] public void BytesOrFile_ResultHasCorrectValues(int bytesOrFile, string contentType, string fileDownloadName, bool enableRangeProcessing, DateTimeOffset lastModified, EntityTagHeaderValue entityTag) { // Arrange @@ -150,12 +151,62 @@ public void BytesOrFile_ResultHasCorrectValues(int bytesOrFile, string contentTy Assert.Equal(entityTag, result.EntityTag); } - public static IEnumerable Bytes_ResultHasCorrectValues_Data => new List + public static IEnumerable BytesOrFile_ResultHasCorrectValues_Data => new List + { + new object[] { 0, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 0, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, + new object[] { 1, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 1, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) } + }; + + [Theory] + [MemberData(nameof(Stream_ResultHasCorrectValues_Data))] + public void Stream_ResultHasCorrectValues(int overload, string contentType, string fileDownloadName, bool enableRangeProcessing, DateTimeOffset lastModified, EntityTagHeaderValue entityTag) + { + // Arrange + var stream = new MemoryStream(); + + // Act + var result = overload switch + { + 0 => Results.Stream(stream, contentType, fileDownloadName, lastModified, entityTag, enableRangeProcessing), + 1 => Results.Stream(PipeReader.Create(stream), contentType, fileDownloadName, lastModified, entityTag, enableRangeProcessing), + _ => Results.Stream((s) => Task.CompletedTask, contentType, fileDownloadName, lastModified, entityTag) + }; + + // Assert + switch (overload) + { + case <= 1: + var fileStreamResult = result as FileStreamHttpResult; + Assert.NotNull(fileStreamResult.FileStream); + Assert.Equal(contentType ?? "application/octet-stream", fileStreamResult.ContentType); + Assert.Equal(fileDownloadName, fileStreamResult.FileDownloadName); + Assert.Equal(enableRangeProcessing, fileStreamResult.EnableRangeProcessing); + Assert.Equal(lastModified, fileStreamResult.LastModified); + Assert.Equal(entityTag, fileStreamResult.EntityTag); + break; + + default: + var pushStreamResult = result as PushStreamHttpResult; + Assert.Equal(contentType ?? "application/octet-stream", pushStreamResult.ContentType); + Assert.Equal(fileDownloadName, pushStreamResult.FileDownloadName); + Assert.False(pushStreamResult.EnableRangeProcessing); + Assert.Equal(lastModified, pushStreamResult.LastModified); + Assert.Equal(entityTag, pushStreamResult.EntityTag); + break; + } + + } + + public static IEnumerable Stream_ResultHasCorrectValues_Data => new List { new object[] { 0, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, new object[] { 0, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, new object[] { 1, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, new object[] { 1, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, + new object[] { 2, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 2, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) } }; [Theory] @@ -656,6 +707,167 @@ public void Problem_WithValidationProblemArg_ResultHasCorrectValues() Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); } + [Fact] + public void ValidationProblem_WithValidationProblemArg_ResultHasCorrectValues() + { + // Arrange + var errors = new Dictionary() { { "testField", new[] { "test error" } } }; + var detail = "test detail"; + var instance = "test instance"; + var statusCode = StatusCodes.Status412PreconditionFailed; // obscure for the test on purpose + var title = "test title"; + var type = "test type"; + var extensions = new Dictionary() { { "testExtension", "test value" } }; + + // Act + // Note: Results.ValidationProblem returns ProblemHttpResult instead of ValidationProblem by design as + // as ValidationProblem doesn't allow setting a custom status code so that it can accurately report + // a single status code in endpoint metadata via its implementation of IEndpointMetadataProvider + var result = Results.ValidationProblem(errors, detail, instance, statusCode, title, type, extensions) as ProblemHttpResult; + + // Assert + Assert.IsType(result.ProblemDetails); + Assert.Equal(errors, ((HttpValidationProblemDetails)result.ProblemDetails).Errors); + Assert.Equal(detail, result.ProblemDetails.Detail); + Assert.Equal(instance, result.ProblemDetails.Instance); + Assert.Equal(statusCode, result.ProblemDetails.Status); + Assert.Equal(statusCode, result.StatusCode); + Assert.Equal(title, result.ProblemDetails.Title); + Assert.Equal(type, result.ProblemDetails.Type); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(extensions, result.ProblemDetails.Extensions); + } + + [Fact] + public void Redirect_WithDefaults_ResultHasCorrectValues() + { + // Arrange + var url = "https://example.com"; + + // Act + var result = Results.Redirect(url) as RedirectHttpResult; + + // Assert + Assert.Equal(url, result.Url); + Assert.False(result.PreserveMethod); + Assert.False(result.Permanent); + Assert.False(result.AcceptLocalUrlOnly); + } + + [Fact] + public void Redirect_WithPermanentTrue_ResultHasCorrectValues() + { + // Arrange + var url = "https://example.com"; + + // Act + var result = Results.Redirect(url, true) as RedirectHttpResult; + + // Assert + Assert.Equal(url, result.Url); + Assert.False(result.PreserveMethod); + Assert.True(result.Permanent); + Assert.False(result.AcceptLocalUrlOnly); + } + + [Fact] + public void Redirect_WithPreserveMethodTrue_ResultHasCorrectValues() + { + // Arrange + var url = "https://example.com"; + + // Act + var result = Results.Redirect(url, false, true) as RedirectHttpResult; + + // Assert + Assert.Equal(url, result.Url); + Assert.True(result.PreserveMethod); + Assert.False(result.Permanent); + Assert.False(result.AcceptLocalUrlOnly); + } + + [Fact] + public void RedirectToRoute_WithRouteNameAndRouteValuesAndFragment_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var routeValues = new { foo = 123 }; + var fragment = "test"; + + // Act + var result = Results.RedirectToRoute(routeName, routeValues, true, true, fragment) as RedirectToRouteHttpResult; + + // Assert + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(routeValues), result.RouteValues); + Assert.True(result.Permanent); + Assert.True(result.PreserveMethod); + Assert.Equal(fragment, result.Fragment); + } + + [Fact] + public void RedirectToRoute_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = Results.RedirectToRoute() as RedirectToRouteHttpResult; + + // Assert + Assert.Null(result.RouteName); + Assert.Null(result.RouteValues); + } + + [Fact] + public void StatusCode_ResultHasCorrectValues() + { + // Arrange + var statusCode = StatusCodes.Status412PreconditionFailed; + + // Act + var result = Results.StatusCode(statusCode) as StatusCodeHttpResult; + + // Assert + Assert.Equal(statusCode, result.StatusCode); + } + + [Fact] + public void Text_WithContentAndContentTypeAndEncoding_ResultHasCorrectValues() + { + // Arrange + var content = "test content"; + var contentType = "text/plain"; + var encoding = Encoding.ASCII; + + // Act + var result = Results.Text(content, contentType, encoding) as ContentHttpResult; + + // Assert + Assert.Null(result.StatusCode); + Assert.Equal(content, result.ResponseContent); + var expectedMediaType = MediaTypeHeaderValue.Parse(contentType); + expectedMediaType.Encoding = encoding; + Assert.Equal(expectedMediaType.ToString(), result.ContentType); + } + + [Fact] + public void Unauthorized_ResultHasCorrectValues() + { + // Act + var result = Results.Unauthorized() as UnauthorizedHttpResult; + + // Assert + Assert.Equal(StatusCodes.Status401Unauthorized, result.StatusCode); + } + + [Fact] + public void UnprocessableEntity_ResultHasCorrectValues() + { + // Act + var result = Results.UnprocessableEntity() as UnprocessableEntity; + + // Assert + Assert.Equal(StatusCodes.Status422UnprocessableEntity, result.StatusCode); + } + [Theory] [MemberData(nameof(FactoryMethodsFromTuples))] public void FactoryMethod_ReturnsCorrectResultType(Expression> expression, Type expectedReturnType) From 2c4d68708839c81a1ea3ff99d95473a8a299bdce Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 15 Apr 2022 18:02:39 -0700 Subject: [PATCH 29/35] Added tests for TypedResults --- .../Http.Results/test/TypedResultsTests.cs | 907 ++++++++++++++++++ 1 file changed, 907 insertions(+) create mode 100644 src/Http/Http.Results/test/TypedResultsTests.cs diff --git a/src/Http/Http.Results/test/TypedResultsTests.cs b/src/Http/Http.Results/test/TypedResultsTests.cs new file mode 100644 index 000000000000..7086772a5dd4 --- /dev/null +++ b/src/Http/Http.Results/test/TypedResultsTests.cs @@ -0,0 +1,907 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.ObjectModel; +using System.IO.Pipelines; +using System.Linq.Expressions; +using System.Reflection; +using System.Security.Claims; +using System.Text; +using System.Text.Json; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Http.HttpResults; + +public class TypedResultsTests +{ + [Fact] + public void Accepted_WithStringUrlAndValue_ResultHasCorrectValues() + { + // Arrange + var uri = "https://example.org"; + var value = new { }; + + // Act + var result = TypedResults.Accepted(uri, value); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(uri, result.Location); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Accepted_WithStringUrl_ResultHasCorrectValues() + { + // Arrange + var uri = "https://example.org"; + + // Act + var result = TypedResults.Accepted(uri); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(uri, result.Location); + } + + [Fact] + public void Accepted_WithNullStringUrl_ResultHasCorrectValues() + { + // Arrange + var uri = default(string); + + // Act + var result = TypedResults.Accepted(uri); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(uri, result.Location); + } + + [Fact] + public void Accepted_WithUriAndValue_ResultHasCorrectValues() + { + // Arrange + var uri = new Uri("https://example.org"); + var value = new { }; + + // Act + var result = TypedResults.Accepted(uri, value); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(uri.ToString(), result.Location); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Accepted_WithUri_ResultHasCorrectValues() + { + // Arrange + var uri = new Uri("https://example.org"); + + // Act + var result = TypedResults.Accepted(uri); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(uri.ToString(), result.Location); + } + + [Fact] + public void Accepted_WithNullUri_ThrowsArgumentNullException() + { + Assert.Throws("uri", () => TypedResults.Accepted(default(Uri))); + } + + [Fact] + public void AcceptedAtRoute_WithRouteNameAndRouteValuesAndValue_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var routeValues = new { foo = 123 }; + var value = new { }; + + // Act + var result = TypedResults.AcceptedAtRoute(value, routeName, routeValues); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(routeValues), result.RouteValues); + Assert.Equal(value, result.Value); + } + + [Fact] + public void AcceptedAtRoute_WithRouteNameAndRouteValues_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var routeValues = new { foo = 123 }; + + // Act + var result = TypedResults.AcceptedAtRoute(routeName, routeValues); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(routeValues), result.RouteValues); + } + + [Fact] + public void AcceptedAtRoute_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = TypedResults.AcceptedAtRoute(); + + // Assert + Assert.Equal(StatusCodes.Status202Accepted, result.StatusCode); + Assert.Null(result.RouteName); + Assert.NotNull(result.RouteValues); + } + + [Fact] + public void BadRequest_WithValue_ResultHasCorrectValues() + { + // Arrange + var value = new { }; + + // Act + var result = TypedResults.BadRequest(value); + + // Assert + Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); + Assert.Equal(value, result.Value); + } + + [Fact] + public void BadRequest_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = TypedResults.BadRequest(); + + // Assert + Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); + } + + [Theory] + [MemberData(nameof(BytesOrFile_ResultHasCorrectValues_Data))] + public void BytesOrFile_ResultHasCorrectValues(int bytesOrFile, string contentType, string fileDownloadName, bool enableRangeProcessing, DateTimeOffset lastModified, EntityTagHeaderValue entityTag) + { + // Arrange + var contents = new byte[0]; + + // Act + var result = bytesOrFile switch + { + 0 => TypedResults.Bytes(contents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag), + _ => TypedResults.File(contents, contentType, fileDownloadName, enableRangeProcessing, lastModified, entityTag) + }; + + // Assert + Assert.Equal(contents, result.FileContents); + Assert.Equal(contentType ?? "application/octet-stream", result.ContentType); + Assert.Equal(fileDownloadName, result.FileDownloadName); + Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing); + Assert.Equal(lastModified, result.LastModified); + Assert.Equal(entityTag, result.EntityTag); + } + + public static IEnumerable BytesOrFile_ResultHasCorrectValues_Data => new List + { + new object[] { 0, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 0, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, + new object[] { 1, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 1, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) } + }; + + [Theory] + [MemberData(nameof(Stream_ResultHasCorrectValues_Data))] + public void Stream_ResultHasCorrectValues(int overload, string contentType, string fileDownloadName, bool enableRangeProcessing, DateTimeOffset lastModified, EntityTagHeaderValue entityTag) + { + // Arrange + var stream = new MemoryStream(); + + // Act + var result = overload switch + { + 0 => TypedResults.Stream(stream, contentType, fileDownloadName, lastModified, entityTag, enableRangeProcessing), + 1 => TypedResults.Stream(PipeReader.Create(stream), contentType, fileDownloadName, lastModified, entityTag, enableRangeProcessing), + _ => (IResult)TypedResults.Stream((s) => Task.CompletedTask, contentType, fileDownloadName, lastModified, entityTag) + }; + + // Assert + switch (overload) + { + case <= 1: + var fileStreamResult = result as FileStreamHttpResult; + Assert.NotNull(fileStreamResult.FileStream); + Assert.Equal(contentType ?? "application/octet-stream", fileStreamResult.ContentType); + Assert.Equal(fileDownloadName, fileStreamResult.FileDownloadName); + Assert.Equal(enableRangeProcessing, fileStreamResult.EnableRangeProcessing); + Assert.Equal(lastModified, fileStreamResult.LastModified); + Assert.Equal(entityTag, fileStreamResult.EntityTag); + break; + + default: + var pushStreamResult = result as PushStreamHttpResult; + Assert.Equal(contentType ?? "application/octet-stream", pushStreamResult.ContentType); + Assert.Equal(fileDownloadName, pushStreamResult.FileDownloadName); + Assert.False(pushStreamResult.EnableRangeProcessing); + Assert.Equal(lastModified, pushStreamResult.LastModified); + Assert.Equal(entityTag, pushStreamResult.EntityTag); + break; + } + + } + + public static IEnumerable Stream_ResultHasCorrectValues_Data => new List + { + new object[] { 0, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 0, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, + new object[] { 1, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 1, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) }, + new object[] { 2, "text/plain", "testfile", true, new DateTimeOffset(2022, 1, 1, 0, 0, 1, TimeSpan.FromHours(-8)), EntityTagHeaderValue.Any }, + new object[] { 2, default(string), default(string), default(bool), default(DateTimeOffset?), default(EntityTagHeaderValue) } + }; + + [Theory] + [MemberData(nameof(ChallengeForbidSignInOut_ResultHasCorrectValues_Data))] + public void Challenge_ResultHasCorrectValues(AuthenticationProperties properties, IList authenticationSchemes) + { + // Act + var result = TypedResults.Challenge(properties, authenticationSchemes); + + // Assert + Assert.Equal(properties, result.Properties); + Assert.Equal(authenticationSchemes ?? new ReadOnlyCollection(new List()), result.AuthenticationSchemes); + } + + [Theory] + [MemberData(nameof(ChallengeForbidSignInOut_ResultHasCorrectValues_Data))] + public void Forbid_ResultHasCorrectValues(AuthenticationProperties properties, IList authenticationSchemes) + { + // Act + var result = TypedResults.Forbid(properties, authenticationSchemes); + + // Assert + Assert.Equal(properties, result.Properties); + Assert.Equal(authenticationSchemes ?? new ReadOnlyCollection(new List()), result.AuthenticationSchemes); + } + + [Theory] + [MemberData(nameof(ChallengeForbidSignInOut_ResultHasCorrectValues_Data))] + public void SignOut_ResultHasCorrectValues(AuthenticationProperties properties, IList authenticationSchemes) + { + // Act + var result = TypedResults.SignOut(properties, authenticationSchemes); + + // Assert + Assert.Equal(properties, result.Properties); + Assert.Equal(authenticationSchemes ?? new ReadOnlyCollection(new List()), result.AuthenticationSchemes); + } + + [Theory] + [MemberData(nameof(ChallengeForbidSignInOut_ResultHasCorrectValues_Data))] + public void SignIn_ResultHasCorrectValues(AuthenticationProperties properties, IList authenticationSchemes) + { + // Arrange + var principal = new ClaimsPrincipal(); + + // Act + var result = TypedResults.SignIn(principal, properties, authenticationSchemes?.First()); + + // Assert + Assert.Equal(principal, result.Principal); + Assert.Equal(properties, result.Properties); + Assert.Equal(authenticationSchemes?.First(), result.AuthenticationScheme); + } + + public static IEnumerable ChallengeForbidSignInOut_ResultHasCorrectValues_Data => new List + { + new object[] { new AuthenticationProperties(), new List { "TestScheme" } }, + new object[] { new AuthenticationProperties(), default(IList) }, + new object[] { default(AuthenticationProperties), new List { "TestScheme" } }, + new object[] { default(AuthenticationProperties), default(IList) }, + }; + + [Fact] + public void SignIn_WithNullPrincipal_ThrowsArgNullException() + { + Assert.Throws("principal", () => TypedResults.SignIn(null)); + } + + [Fact] + public void Conflict_WithValue_ResultHasCorrectValues() + { + // Arrange + var value = new { }; + + // Act + var result = TypedResults.Conflict(value); + + // Assert + Assert.Equal(StatusCodes.Status409Conflict, result.StatusCode); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Conflict_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = TypedResults.Conflict(); + + // Assert + Assert.Equal(StatusCodes.Status409Conflict, result.StatusCode); + } + + [Fact] + public void Content_WithContentAndMediaType_ResultHasCorrectValues() + { + // Arrange + var content = "test content"; + var mediaType = MediaTypeHeaderValue.Parse("text/plain"); + + // Act + var result = TypedResults.Content(content, mediaType); + + // Assert + Assert.Null(result.StatusCode); + Assert.Equal(content, result.ResponseContent); + Assert.Equal(mediaType.ToString(), result.ContentType); + } + + [Fact] + public void Content_WithContentAndContentTypeAndEncoding_ResultHasCorrectValues() + { + // Arrange + var content = "test content"; + var contentType = "text/plain"; + var encoding = Encoding.UTF8; + + // Act + var result = TypedResults.Content(content, contentType, null); + + // Assert + Assert.Null(result.StatusCode); + Assert.Equal(content, result.ResponseContent); + Assert.Equal(contentType, result.ContentType); + } + + [Fact] + public void Created_WithStringUriAndValue_ResultHasCorrectValues() + { + // Arrange + var uri = "https://example.com/entity"; + var value = new { }; + + // Act + var result = TypedResults.Created(uri, value); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(uri, result.Location); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Created_WithStringUri_ResultHasCorrectValues() + { + // Arrange + var uri = "https://example.com/entity"; + + // Act + var result = TypedResults.Created(uri); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(uri, result.Location); + } + + [Fact] + public void Created_WithUriAndValue_ResultHasCorrectValues() + { + // Arrange + var uri = new Uri("https://example.com/entity"); + var value = new { }; + + // Act + var result = TypedResults.Created(uri, value); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(uri.ToString(), result.Location); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Created_WithUri_ResultHasCorrectValues() + { + // Arrange + var uri = new Uri("https://example.com/entity"); + + // Act + var result = TypedResults.Created(uri); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(uri.ToString(), result.Location); + } + + [Fact] + public void Created_WithNullStringUri_ThrowsArgNullException() + { + Assert.Throws("uri", () => TypedResults.Created(default(string))); + } + + [Fact] + public void Created_WithNullUri_ThrowsArgNullException() + { + Assert.Throws("uri", () => TypedResults.Created(default(Uri))); + } + + [Fact] + public void CreatedAtRoute_WithRouteNameAndRouteValuesAndValue_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var routeValues = new { foo = 123 }; + var value = new { }; + + // Act + var result = TypedResults.CreatedAtRoute(value, routeName, routeValues); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(routeValues), result.RouteValues); + Assert.Equal(value, result.Value); + } + + [Fact] + public void CreatedAtRoute_WithRouteNameAndValue_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var value = new { }; + + // Act + var result = TypedResults.CreatedAtRoute(value, routeName, null); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(), result.RouteValues); + Assert.Equal(value, result.Value); + } + + [Fact] + public void CreatedAtRoute_WithRouteName_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + + // Act + var result = TypedResults.CreatedAtRoute(routeName, default(object)); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(), result.RouteValues); + } + + [Fact] + public void CreatedAtRoute_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = TypedResults.CreatedAtRoute(); + + // Assert + Assert.Equal(StatusCodes.Status201Created, result.StatusCode); + Assert.Null(result.RouteName); + Assert.Equal(new RouteValueDictionary(), result.RouteValues); + } + + [Fact] + public void Empty_IsEmptyInstance() + { + // Act + var result = TypedResults.Empty; + + // Assert + Assert.Equal(EmptyHttpResult.Instance, result); + } + + [Fact] + public void Json_WithAllArgs_ResultHasCorrectValues() + { + // Arrange + var data = new { }; + var options = new JsonSerializerOptions(); + var contentType = "application/custom+json"; + var statusCode = StatusCodes.Status208AlreadyReported; + + // Act + var result = TypedResults.Json(data, options, contentType, statusCode); + + // Assert + Assert.Equal(data, result.Value); + Assert.Equal(options, result.JsonSerializerOptions); + Assert.Equal(contentType, result.ContentType); + Assert.Equal(statusCode, result.StatusCode); + } + + [Fact] + public void Json_WithNoArgs_ResultHasCorrectValues() + { + // Arrange + var data = default(object); + + // Act + var result = TypedResults.Json(data); + + // Assert + Assert.Null(result.Value); + Assert.Null(result.JsonSerializerOptions); + Assert.Null(result.ContentType); + Assert.Null(result.StatusCode); + } + + [Fact] + public void LocalRedirect_WithUrl_ResultHasCorrectValues() + { + // Arrange + var localUrl = "test/path"; + + // Act + var result = TypedResults.LocalRedirect(localUrl); + + // Assert + Assert.Equal(localUrl, result.Url); + Assert.True(result.AcceptLocalUrlOnly); + Assert.False(result.Permanent); + Assert.False(result.PreserveMethod); + } + + [Fact] + public void LocalRedirect_WithUrlAndPermanentTrue_ResultHasCorrectValues() + { + // Arrange + var localUrl = "test/path"; + var permanent = true; + + // Act + var result = TypedResults.LocalRedirect(localUrl, permanent); + + // Assert + Assert.Equal(localUrl, result.Url); + Assert.True(result.AcceptLocalUrlOnly); + Assert.True(result.Permanent); + Assert.False(result.PreserveMethod); + } + + [Fact] + public void LocalRedirect_WithUrlAndPermanentTrueAndPreserveTrue_ResultHasCorrectValues() + { + // Arrange + var localUrl = "test/path"; + var permanent = true; + var preserveMethod = true; + + // Act + var result = TypedResults.LocalRedirect(localUrl, permanent, preserveMethod); + + // Assert + Assert.Equal(localUrl, result.Url); + Assert.True(result.AcceptLocalUrlOnly); + Assert.True(result.Permanent); + Assert.True(result.PreserveMethod); + } + + [Fact] + public void LocalRedirect_WithNonLocalUrlAndPermanentTrueAndPreserveTrue_ResultHasCorrectValues() + { + // Arrange + var localUrl = "https://example.com/non-local-url/example"; + var permanent = true; + var preserveMethod = true; + + // Act + var result = TypedResults.LocalRedirect(localUrl, permanent, preserveMethod); + + // Assert + Assert.Equal(localUrl, result.Url); + Assert.True(result.AcceptLocalUrlOnly); + Assert.True(result.Permanent); + Assert.True(result.PreserveMethod); + } + + [Fact] + public void NoContent_ResultHasCorrectValues() + { + // Act + var result = TypedResults.NoContent() as NoContent; + + // Assert + Assert.Equal(StatusCodes.Status204NoContent, result.StatusCode); + } + + [Fact] + public void NotFound_WithValue_ResultHasCorrectValues() + { + // Arrange + var value = new { }; + + // Act + var result = TypedResults.NotFound(value); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, result.StatusCode); + Assert.Equal(value, result.Value); + } + + [Fact] + public void NotFound_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = TypedResults.NotFound(); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, result.StatusCode); + } + + [Fact] + public void Ok_WithValue_ResultHasCorrectValues() + { + // Arrange + var value = new { }; + + // Act + var result = TypedResults.Ok(value); + + // Assert + Assert.Equal(StatusCodes.Status200OK, result.StatusCode); + Assert.Equal(value, result.Value); + } + + [Fact] + public void Ok_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = TypedResults.Ok(); + + // Assert + Assert.Equal(StatusCodes.Status200OK, result.StatusCode); + } + + [Fact] + public void Problem_WithArgs_ResultHasCorrectValues() + { + // Arrange + var detail = "test detail"; + var instance = "test instance"; + var statusCode = StatusCodes.Status409Conflict; + var title = "test title"; + var type = "test type"; + var extensions = new Dictionary { { "test", "value" } }; + + // Act + var result = TypedResults.Problem(detail, instance, statusCode, title, type, extensions); + + // Assert + Assert.Equal(detail, result.ProblemDetails.Detail); + Assert.Equal(instance, result.ProblemDetails.Instance); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(statusCode, result.StatusCode); + Assert.Equal(title, result.ProblemDetails.Title); + Assert.Equal(type, result.ProblemDetails.Type); + Assert.Equal(extensions, result.ProblemDetails.Extensions); + } + + [Fact] + public void Problem_WithNoArgs_ResultHasCorrectValues() + { + /// Act + var result = TypedResults.Problem(); + + // Assert + Assert.Null(result.ProblemDetails.Detail); + Assert.Null(result.ProblemDetails.Instance); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(StatusCodes.Status500InternalServerError, result.StatusCode); + Assert.Equal("An error occurred while processing your request.", result.ProblemDetails.Title); + Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.6.1", result.ProblemDetails.Type); + Assert.Empty(result.ProblemDetails.Extensions); + } + + [Fact] + public void Problem_WithProblemArg_ResultHasCorrectValues() + { + // Arrange + var problem = new ProblemDetails { Title = "Test title" }; + + // Act + var result = TypedResults.Problem(problem); + + // Assert + Assert.Equal(problem, result.ProblemDetails); + Assert.Equal("Test title", result.ProblemDetails.Title); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(StatusCodes.Status500InternalServerError, result.StatusCode); + } + + [Fact] + public void Problem_WithValidationProblemArg_ResultHasCorrectValues() + { + // Arrange + var problem = new HttpValidationProblemDetails { Title = "Test title" }; + + // Act + var result = TypedResults.Problem(problem); + + // Assert + Assert.Equal(problem, result.ProblemDetails); + Assert.Equal("Test title", result.ProblemDetails.Title); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); + } + + [Fact] + public void ValidationProblem_WithValidationProblemArg_ResultHasCorrectValues() + { + // Arrange + var errors = new Dictionary() { { "testField", new[] { "test error" } } }; + var detail = "test detail"; + var instance = "test instance"; + var title = "test title"; + var type = "test type"; + var extensions = new Dictionary() { { "testExtension", "test value" } }; + + // Act + var result = TypedResults.ValidationProblem(errors, detail, instance, title, type, extensions); + + // Assert + Assert.Equal(errors, result.ProblemDetails.Errors); + Assert.Equal(detail, result.ProblemDetails.Detail); + Assert.Equal(instance, result.ProblemDetails.Instance); + Assert.Equal(StatusCodes.Status400BadRequest, result.ProblemDetails.Status); + Assert.Equal(StatusCodes.Status400BadRequest, result.StatusCode); + Assert.Equal(title, result.ProblemDetails.Title); + Assert.Equal(type, result.ProblemDetails.Type); + Assert.Equal("application/problem+json", result.ContentType); + Assert.Equal(extensions, result.ProblemDetails.Extensions); + } + + [Fact] + public void Redirect_WithDefaults_ResultHasCorrectValues() + { + // Arrange + var url = "https://example.com"; + + // Act + var result = TypedResults.Redirect(url); + + // Assert + Assert.Equal(url, result.Url); + Assert.False(result.PreserveMethod); + Assert.False(result.Permanent); + Assert.False(result.AcceptLocalUrlOnly); + } + + [Fact] + public void Redirect_WithPermanentTrue_ResultHasCorrectValues() + { + // Arrange + var url = "https://example.com"; + + // Act + var result = TypedResults.Redirect(url, true); + + // Assert + Assert.Equal(url, result.Url); + Assert.False(result.PreserveMethod); + Assert.True(result.Permanent); + Assert.False(result.AcceptLocalUrlOnly); + } + + [Fact] + public void Redirect_WithPreserveMethodTrue_ResultHasCorrectValues() + { + // Arrange + var url = "https://example.com"; + + // Act + var result = TypedResults.Redirect(url, false, true); + + // Assert + Assert.Equal(url, result.Url); + Assert.True(result.PreserveMethod); + Assert.False(result.Permanent); + Assert.False(result.AcceptLocalUrlOnly); + } + + [Fact] + public void RedirectToRoute_WithRouteNameAndRouteValuesAndFragment_ResultHasCorrectValues() + { + // Arrange + var routeName = "routeName"; + var routeValues = new { foo = 123 }; + var fragment = "test"; + + // Act + var result = TypedResults.RedirectToRoute(routeName, routeValues, true, true, fragment); + + // Assert + Assert.Equal(routeName, result.RouteName); + Assert.Equal(new RouteValueDictionary(routeValues), result.RouteValues); + Assert.True(result.Permanent); + Assert.True(result.PreserveMethod); + Assert.Equal(fragment, result.Fragment); + } + + [Fact] + public void RedirectToRoute_WithNoArgs_ResultHasCorrectValues() + { + // Act + var result = TypedResults.RedirectToRoute(); + + // Assert + Assert.Null(result.RouteName); + Assert.Null(result.RouteValues); + } + + [Fact] + public void StatusCode_ResultHasCorrectValues() + { + // Arrange + var statusCode = StatusCodes.Status412PreconditionFailed; + + // Act + var result = TypedResults.StatusCode(statusCode); + + // Assert + Assert.Equal(statusCode, result.StatusCode); + } + + [Fact] + public void Text_WithContentAndContentTypeAndEncoding_ResultHasCorrectValues() + { + // Arrange + var content = "test content"; + var contentType = "text/plain"; + var encoding = Encoding.ASCII; + + // Act + var result = TypedResults.Text(content, contentType, encoding); + + // Assert + Assert.Null(result.StatusCode); + Assert.Equal(content, result.ResponseContent); + var expectedMediaType = MediaTypeHeaderValue.Parse(contentType); + expectedMediaType.Encoding = encoding; + Assert.Equal(expectedMediaType.ToString(), result.ContentType); + } + + [Fact] + public void Unauthorized_ResultHasCorrectValues() + { + // Act + var result = TypedResults.Unauthorized(); + + // Assert + Assert.Equal(StatusCodes.Status401Unauthorized, result.StatusCode); + } + + [Fact] + public void UnprocessableEntity_ResultHasCorrectValues() + { + // Act + var result = TypedResults.UnprocessableEntity(); + + // Assert + Assert.Equal(StatusCodes.Status422UnprocessableEntity, result.StatusCode); + } +} From 36b40bc4b819129fe0e348d5dcecf499b9cf612f Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 15 Apr 2022 18:18:26 -0700 Subject: [PATCH 30/35] Revert changes to MinimalSample --- src/Http/samples/MinimalSample/MinimalSample.csproj | 6 ------ src/Http/samples/MinimalSample/Program.cs | 5 ----- 2 files changed, 11 deletions(-) diff --git a/src/Http/samples/MinimalSample/MinimalSample.csproj b/src/Http/samples/MinimalSample/MinimalSample.csproj index 0f2526083adc..eea90b96520b 100644 --- a/src/Http/samples/MinimalSample/MinimalSample.csproj +++ b/src/Http/samples/MinimalSample/MinimalSample.csproj @@ -2,11 +2,6 @@ $(DefaultNetCoreTargetFramework) - - true - - - true @@ -18,7 +13,6 @@ - diff --git a/src/Http/samples/MinimalSample/Program.cs b/src/Http/samples/MinimalSample/Program.cs index 12ec6497f3fb..f2f50d8c274c 100644 --- a/src/Http/samples/MinimalSample/Program.cs +++ b/src/Http/samples/MinimalSample/Program.cs @@ -6,15 +6,10 @@ var builder = WebApplication.CreateBuilder(args); -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); - var app = builder.Build(); if (app.Environment.IsDevelopment()) { - app.MapSwagger(); - app.UseSwaggerUI(); app.UseDeveloperExceptionPage(); } From 38bead6d4bc53f2a39ca521739455e05d4ba7163 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Fri, 15 Apr 2022 21:24:16 -0700 Subject: [PATCH 31/35] Remove MinimalSample from RequiresDelayedBuildProjects --- eng/RequiresDelayedBuildProjects.props | 1 - 1 file changed, 1 deletion(-) diff --git a/eng/RequiresDelayedBuildProjects.props b/eng/RequiresDelayedBuildProjects.props index a71e43db8269..0951a943c555 100644 --- a/eng/RequiresDelayedBuildProjects.props +++ b/eng/RequiresDelayedBuildProjects.props @@ -16,6 +16,5 @@ - From 60943eb7faf7fb5605658391eca55876b1afdec7 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Sat, 16 Apr 2022 12:53:39 -0700 Subject: [PATCH 32/35] Fix test on Unix --- src/Http/Http.Results/test/ResultsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/Http.Results/test/ResultsTests.cs b/src/Http/Http.Results/test/ResultsTests.cs index 4530c9babb2e..213163608c06 100644 --- a/src/Http/Http.Results/test/ResultsTests.cs +++ b/src/Http/Http.Results/test/ResultsTests.cs @@ -918,7 +918,7 @@ private static string GetMemberName(Expression expression) (() => Results.Empty, typeof(EmptyHttpResult)), (() => Results.File(new byte[0], null, null, false, null, null), typeof(FileContentHttpResult)), (() => Results.File(new MemoryStream(), null, null, null, null, false), typeof(FileStreamHttpResult)), - (() => Results.File("C:\\path", null, null, null, null, false), typeof(PhysicalFileHttpResult)), + (() => Results.File(Path.Join(Path.DirectorySeparatorChar.ToString(), "rooted", "path"), null, null, null, null, false), typeof(PhysicalFileHttpResult)), (() => Results.File("path", null, null, null, null, false), typeof(VirtualFileHttpResult)), (() => Results.Forbid(null, null), typeof(ForbidHttpResult)), (() => Results.Json(new(), null, null, null), typeof(JsonHttpResult)), From f551d7b0a2356c1d7857f5760842cd05c886d60e Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Mon, 18 Apr 2022 10:22:12 -0700 Subject: [PATCH 33/35] Consistency fixes --- src/Http/Http.Results/src/CreatedAtRoute.cs | 2 +- src/Http/Http.Results/src/CreatedAtRouteOfT.cs | 2 +- src/Http/Http.Results/src/PublicAPI.Unshipped.txt | 5 ++--- src/Http/Http.Results/src/ValidationProblem.cs | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Http/Http.Results/src/CreatedAtRoute.cs b/src/Http/Http.Results/src/CreatedAtRoute.cs index 3e7e7fccf4d1..7cb9b31f0b53 100644 --- a/src/Http/Http.Results/src/CreatedAtRoute.cs +++ b/src/Http/Http.Results/src/CreatedAtRoute.cs @@ -47,7 +47,7 @@ internal CreatedAtRoute( /// /// Gets the route data to use for generating the URL. /// - public RouteValueDictionary? RouteValues { get; } + public RouteValueDictionary RouteValues { get; } /// /// Gets the HTTP status code: diff --git a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs index de158f722cc0..c4260b27f0a9 100644 --- a/src/Http/Http.Results/src/CreatedAtRouteOfT.cs +++ b/src/Http/Http.Results/src/CreatedAtRouteOfT.cs @@ -58,7 +58,7 @@ internal CreatedAtRoute( /// /// Gets the route data to use for generating the URL. /// - public RouteValueDictionary? RouteValues { get; } + public RouteValueDictionary RouteValues { get; } /// /// Gets the HTTP status code: diff --git a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt index 8191ee8a973a..e87a32cfd7d1 100644 --- a/src/Http/Http.Results/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Results/src/PublicAPI.Unshipped.txt @@ -54,12 +54,12 @@ Microsoft.AspNetCore.Http.HttpResults.Created.Value.get -> TValue? Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteName.get -> string? -Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary! Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.StatusCode.get -> int Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.ExecuteAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.Task! Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteName.get -> string? -Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary? +Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.RouteValues.get -> Microsoft.AspNetCore.Routing.RouteValueDictionary! Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.StatusCode.get -> int Microsoft.AspNetCore.Http.HttpResults.CreatedAtRoute.Value.get -> TValue? Microsoft.AspNetCore.Http.HttpResults.EmptyHttpResult @@ -217,7 +217,6 @@ static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult3 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult1 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! static Microsoft.AspNetCore.Http.HttpResults.Results.implicit operator Microsoft.AspNetCore.Http.HttpResults.Results!(TResult2 result) -> Microsoft.AspNetCore.Http.HttpResults.Results! -static Microsoft.AspNetCore.Http.HttpResults.ValidationProblem.PopulateMetadata(Microsoft.AspNetCore.Http.Metadata.EndpointMetadataContext! context) -> void static Microsoft.AspNetCore.Http.Results.Bytes(System.ReadOnlyMemory contents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.IResult! static Microsoft.AspNetCore.Http.Results.Empty.get -> Microsoft.AspNetCore.Http.IResult! static Microsoft.AspNetCore.Http.Results.Stream(System.Func! streamWriterCallback, string? contentType = null, string? fileDownloadName = null, System.DateTimeOffset? lastModified = null, Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag = null) -> Microsoft.AspNetCore.Http.IResult! diff --git a/src/Http/Http.Results/src/ValidationProblem.cs b/src/Http/Http.Results/src/ValidationProblem.cs index f0f06ef575e4..9812ec9ce0dc 100644 --- a/src/Http/Http.Results/src/ValidationProblem.cs +++ b/src/Http/Http.Results/src/ValidationProblem.cs @@ -57,7 +57,7 @@ public Task ExecuteAsync(HttpContext httpContext) } /// - public static void PopulateMetadata(EndpointMetadataContext context) + static void IEndpointMetadataProvider.PopulateMetadata(EndpointMetadataContext context) { context.EndpointMetadata.Add(new ProducesResponseTypeMetadata(typeof(HttpValidationProblemDetails), StatusCodes.Status400BadRequest, "application/problem+json")); } From bed172db6f4c517e3b32d758132bf06e22a1cdd9 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Mon, 18 Apr 2022 12:22:48 -0700 Subject: [PATCH 34/35] Update googletest --- src/submodules/googletest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/submodules/googletest b/src/submodules/googletest index af29db7ec28d..80600e56cc9a 160000 --- a/src/submodules/googletest +++ b/src/submodules/googletest @@ -1 +1 @@ -Subproject commit af29db7ec28d6df1c7f0f745186884091e602e07 +Subproject commit 80600e56cc9afe7ee02737429f9177aa87025054 From d0dc8c7ca10bd938e1378f858dd9af8b1f429663 Mon Sep 17 00:00:00 2001 From: Damian Edwards Date: Mon, 18 Apr 2022 14:53:05 -0700 Subject: [PATCH 35/35] PR feedback --- src/Http/Http.Results/src/HttpResultsHelper.cs | 1 - src/Http/Http.Results/src/Results.cs | 2 +- src/Http/Http.Results/src/TypedResults.cs | 14 +++++++------- .../Http.Results/test/BadRequestResultTests.cs | 2 +- src/Http/Http.Results/test/JsonResultTests.cs | 2 +- src/Http/Http.Results/test/TypedResultsTests.cs | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Http/Http.Results/src/HttpResultsHelper.cs b/src/Http/Http.Results/src/HttpResultsHelper.cs index f510def3d8b7..b899467b1d80 100644 --- a/src/Http/Http.Results/src/HttpResultsHelper.cs +++ b/src/Http/Http.Results/src/HttpResultsHelper.cs @@ -32,7 +32,6 @@ public static Task WriteResultAsJsonAsync( return httpContext.Response.WriteAsJsonAsync( value, - value.GetType(), options: jsonSerializerOptions, contentType: contentType); } diff --git a/src/Http/Http.Results/src/Results.cs b/src/Http/Http.Results/src/Results.cs index f44dcfebdb5e..005ea1385a63 100644 --- a/src/Http/Http.Results/src/Results.cs +++ b/src/Http/Http.Results/src/Results.cs @@ -406,7 +406,7 @@ public static IResult RedirectToRoute(string? routeName = null, object? routeVal => TypedResults.RedirectToRoute(routeName, routeValues, permanent, preserveMethod, fragment); /// - /// Creates a object by specifying a . + /// Creates an object by specifying a . /// /// The status code to set on the response. /// The created object for the response. diff --git a/src/Http/Http.Results/src/TypedResults.cs b/src/Http/Http.Results/src/TypedResults.cs index fb7edba9f999..938400a4169b 100644 --- a/src/Http/Http.Results/src/TypedResults.cs +++ b/src/Http/Http.Results/src/TypedResults.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Http; public static class TypedResults { /// - /// Creates an that on execution invokes . + /// Creates a that on execution invokes . /// /// The behavior of this method depends on the in use. /// and @@ -54,7 +54,7 @@ public static ForbidHttpResult Forbid(AuthenticationProperties? properties = nul => new(authenticationSchemes: authenticationSchemes ?? Array.Empty(), properties); /// - /// Creates an that on execution invokes . + /// Creates a that on execution invokes . /// /// The containing the user claims. /// used to perform the sign-in operation. @@ -67,7 +67,7 @@ public static SignInHttpResult SignIn( => new(principal, authenticationScheme, properties); /// - /// Creates an that on execution invokes . + /// Creates a that on execution invokes . /// /// used to perform the sign-out operation. /// The authentication scheme to use for the sign-out operation. @@ -164,7 +164,7 @@ public static JsonHttpResult Json(TValue? data, JsonSerializerOp #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static FileContentHttpResult File( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - byte[] fileContents, + byte[] fileContents, string? contentType = null, string? fileDownloadName = null, bool enableRangeProcessing = false, @@ -325,7 +325,7 @@ public static FileStreamHttpResult Stream( } /// - /// Writes the contents of specified to the response. + /// Writes the contents of the specified to the response. /// /// This supports range requests ( or /// if the range is not satisfiable). @@ -411,7 +411,7 @@ public static PushStreamHttpResult Stream( #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static PhysicalFileHttpResult PhysicalFile( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - string path, + string path, string? contentType = null, string? fileDownloadName = null, DateTimeOffset? lastModified = null, @@ -444,7 +444,7 @@ public static PhysicalFileHttpResult PhysicalFile( #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters public static VirtualFileHttpResult VirtualFile( #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters - string path, + string path, string? contentType = null, string? fileDownloadName = null, DateTimeOffset? lastModified = null, diff --git a/src/Http/Http.Results/test/BadRequestResultTests.cs b/src/Http/Http.Results/test/BadRequestResultTests.cs index f6078d5a8303..30286b384bc9 100644 --- a/src/Http/Http.Results/test/BadRequestResultTests.cs +++ b/src/Http/Http.Results/test/BadRequestResultTests.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults; public class BadRequestResultTests { [Fact] - public void BadRequestObjectResult_SetsStatusCodeA() + public void BadRequestObjectResult_SetsStatusCode() { // Arrange & Act var badRequestResult = new BadRequest(); diff --git a/src/Http/Http.Results/test/JsonResultTests.cs b/src/Http/Http.Results/test/JsonResultTests.cs index 09f90d04fa3d..d0804b3ab4d3 100644 --- a/src/Http/Http.Results/test/JsonResultTests.cs +++ b/src/Http/Http.Results/test/JsonResultTests.cs @@ -71,7 +71,7 @@ public async Task JsonResult_ExecuteAsync_JsonSerializesBody() } [Fact] - public async Task JsonResult_ExecuteAsync_JsonSerializesBody_WitOptions() + public async Task JsonResult_ExecuteAsync_JsonSerializesBody_WithOptions() { // Arrange var jsonOptions = new JsonSerializerOptions() diff --git a/src/Http/Http.Results/test/TypedResultsTests.cs b/src/Http/Http.Results/test/TypedResultsTests.cs index 7086772a5dd4..c927bd942345 100644 --- a/src/Http/Http.Results/test/TypedResultsTests.cs +++ b/src/Http/Http.Results/test/TypedResultsTests.cs @@ -623,7 +623,7 @@ public void LocalRedirect_WithNonLocalUrlAndPermanentTrueAndPreserveTrue_ResultH public void NoContent_ResultHasCorrectValues() { // Act - var result = TypedResults.NoContent() as NoContent; + var result = TypedResults.NoContent(); // Assert Assert.Equal(StatusCodes.Status204NoContent, result.StatusCode);