Skip to content

Commit

Permalink
Separate IResult based results from ActionResults (#33843)
Browse files Browse the repository at this point in the history
* Separate IResult based results from ActionResults

Fixes #33729
  • Loading branch information
pranavkm authored Jun 30, 2021
1 parent ed383aa commit b9efadc
Show file tree
Hide file tree
Showing 126 changed files with 7,369 additions and 3,144 deletions.
33 changes: 33 additions & 0 deletions AspNetCore.sln
Original file line number Diff line number Diff line change
Expand Up @@ -1626,6 +1626,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Compon
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleWebSiteWithWebApplicationBuilderException", "src\Mvc\test\WebSites\SimpleWebSiteWithWebApplicationBuilderException\SimpleWebSiteWithWebApplicationBuilderException.csproj", "{5C641396-7E92-4F5C-A5A1-B4CDF480539B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Http.Results", "Http.Results", "{323C3EB6-1D15-4B3D-918D-699D7F64DED9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Results", "src\Http\Http.Results\src\Microsoft.AspNetCore.Http.Results.csproj", "{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Results.Tests", "src\Http\Http.Results\test\Microsoft.AspNetCore.Http.Results.Tests.csproj", "{F599EAA6-399F-4A91-9B1F-D311305B43D9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Logging.W3C.Sample", "src\Middleware\HttpLogging\samples\Logging.W3C.Sample\Logging.W3C.Sample.csproj", "{17459B97-1AA3-4154-83D3-C6BDC9FA3F85}"
EndProject
Global
Expand Down Expand Up @@ -7747,6 +7753,30 @@ Global
{5C641396-7E92-4F5C-A5A1-B4CDF480539B}.Release|x64.Build.0 = Release|Any CPU
{5C641396-7E92-4F5C-A5A1-B4CDF480539B}.Release|x86.ActiveCfg = Release|Any CPU
{5C641396-7E92-4F5C-A5A1-B4CDF480539B}.Release|x86.Build.0 = Release|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Debug|x64.ActiveCfg = Debug|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Debug|x64.Build.0 = Debug|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Debug|x86.ActiveCfg = Debug|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Debug|x86.Build.0 = Debug|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Release|Any CPU.Build.0 = Release|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Release|x64.ActiveCfg = Release|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Release|x64.Build.0 = Release|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Release|x86.ActiveCfg = Release|Any CPU
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8}.Release|x86.Build.0 = Release|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Debug|x64.ActiveCfg = Debug|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Debug|x64.Build.0 = Debug|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Debug|x86.ActiveCfg = Debug|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Debug|x86.Build.0 = Debug|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Release|Any CPU.Build.0 = Release|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Release|x64.ActiveCfg = Release|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Release|x64.Build.0 = Release|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Release|x86.ActiveCfg = Release|Any CPU
{F599EAA6-399F-4A91-9B1F-D311305B43D9}.Release|x86.Build.0 = Release|Any CPU
{17459B97-1AA3-4154-83D3-C6BDC9FA3F85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17459B97-1AA3-4154-83D3-C6BDC9FA3F85}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17459B97-1AA3-4154-83D3-C6BDC9FA3F85}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -8564,6 +8594,9 @@ Global
{558C46DE-DE16-41D5-8DB7-D6D748E32977} = {3EC71A0E-6515-4A5A-B759-F0BCF1BCFC56}
{B1AA24A4-5E02-4DC1-B57F-6EB03F91E4DD} = {44963D50-8B58-44E6-918D-788BCB406695}
{5C641396-7E92-4F5C-A5A1-B4CDF480539B} = {088C37A5-30D2-40FB-B031-D163CFBED006}
{323C3EB6-1D15-4B3D-918D-699D7F64DED9} = {627BE8B3-59E6-4F1D-8C9C-76B804D41724}
{092EA9F6-84D4-41EF-A618-BDA50A0E10A8} = {323C3EB6-1D15-4B3D-918D-699D7F64DED9}
{F599EAA6-399F-4A91-9B1F-D311305B43D9} = {323C3EB6-1D15-4B3D-918D-699D7F64DED9}
{17459B97-1AA3-4154-83D3-C6BDC9FA3F85} = {022B4B80-E813-4256-8034-11A68146F4EF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
Expand Down
1 change: 1 addition & 0 deletions eng/ProjectReferences.props
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http.Abstractions" ProjectPath="$(RepoRoot)src\Http\Http.Abstractions\src\Microsoft.AspNetCore.Http.Abstractions.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http.Extensions" ProjectPath="$(RepoRoot)src\Http\Http.Extensions\src\Microsoft.AspNetCore.Http.Extensions.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http.Features" ProjectPath="$(RepoRoot)src\Http\Http.Features\src\Microsoft.AspNetCore.Http.Features.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http.Results" ProjectPath="$(RepoRoot)src\Http\Http.Results\src\Microsoft.AspNetCore.Http.Results.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http" ProjectPath="$(RepoRoot)src\Http\Http\src\Microsoft.AspNetCore.Http.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Metadata" ProjectPath="$(RepoRoot)src\Http\Metadata\src\Microsoft.AspNetCore.Metadata.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Owin" ProjectPath="$(RepoRoot)src\Http\Owin\src\Microsoft.AspNetCore.Owin.csproj" />
Expand Down
1 change: 1 addition & 0 deletions eng/SharedFramework.Local.props
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http.Abstractions" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http.Extensions" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http.Features" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http.Results" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Routing.Abstractions" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Routing" />
Expand Down
2 changes: 2 additions & 0 deletions src/Framework/test/TestData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static TestData()
"Microsoft.AspNetCore.Http.Connections.Common",
"Microsoft.AspNetCore.Http.Extensions",
"Microsoft.AspNetCore.Http.Features",
"Microsoft.AspNetCore.Http.Results",
"Microsoft.AspNetCore.HttpLogging",
"Microsoft.AspNetCore.HttpOverrides",
"Microsoft.AspNetCore.HttpsPolicy",
Expand Down Expand Up @@ -188,6 +189,7 @@ static TestData()
{ "Microsoft.AspNetCore.Http.Connections.Common", "6.0.0.0" },
{ "Microsoft.AspNetCore.Http.Extensions", "6.0.0.0" },
{ "Microsoft.AspNetCore.Http.Features", "6.0.0.0" },
{ "Microsoft.AspNetCore.Http.Results", "6.0.0.0" },
{ "Microsoft.AspNetCore.HttpLogging", "6.0.0.0" },
{ "Microsoft.AspNetCore.HttpOverrides", "6.0.0.0" },
{ "Microsoft.AspNetCore.HttpsPolicy", "6.0.0.0" },
Expand Down
68 changes: 68 additions & 0 deletions src/Http/Http.Results/src/AcceptedAtRouteResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Http.Result
{
internal sealed class AcceptedAtRouteResult : ObjectResult
{
/// <summary>
/// Initializes a new instance of the <see cref="AcceptedAtRouteResult"/> class with the values
/// provided.
/// </summary>
/// <param name="routeValues">The route data to use for generating the URL.</param>
/// <param name="value">The value to format in the entity body.</param>
public AcceptedAtRouteResult(object? routeValues, object? value)
: this(routeName: null, routeValues: routeValues, value: value)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="AcceptedAtRouteResult"/> class with the values
/// provided.
/// </summary>
/// <param name="routeName">The name of the route to use for generating the URL.</param>
/// <param name="routeValues">The route data to use for generating the URL.</param>
/// <param name="value">The value to format in the entity body.</param>
public AcceptedAtRouteResult(
string? routeName,
object? routeValues,
object? value)
: base(value, StatusCodes.Status202Accepted)
{
RouteName = routeName;
RouteValues = new RouteValueDictionary(routeValues);
}

/// <summary>
/// Gets the name of the route to use for generating the URL.
/// </summary>
public string? RouteName { get; }

/// <summary>
/// Gets the route data to use for generating the URL.
/// </summary>
public RouteValueDictionary RouteValues { get; }

/// <inheritdoc />
protected override void OnFormatting(HttpContext context)
{
var linkGenerator = context.RequestServices.GetRequiredService<LinkGenerator>();
var url = linkGenerator.GetUriByAddress(
context,
RouteName,
RouteValues,
fragment: FragmentString.Empty);

if (string.IsNullOrEmpty(url))
{
throw new InvalidOperationException("No route matches the supplied values.");
}

context.Response.Headers.Location = url;
}
}
}
74 changes: 74 additions & 0 deletions src/Http/Http.Results/src/AcceptedResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;

namespace Microsoft.AspNetCore.Http.Result
{
internal sealed class AcceptedResult : ObjectResult
{
/// <summary>
/// Initializes a new instance of the <see cref="AcceptedResult"/> class with the values
/// provided.
/// </summary>
public AcceptedResult()
: base(value: null, StatusCodes.Status202Accepted)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="AcceptedResult"/> class with the values
/// provided.
/// </summary>
/// <param name="location">The location at which the status of requested content can be monitored.</param>
/// <param name="value">The value to format in the entity body.</param>
public AcceptedResult(string? location, object? value)
: base(value, StatusCodes.Status202Accepted)
{
Location = location;
}

/// <summary>
/// Initializes a new instance of the <see cref="AcceptedResult"/> class with the values
/// provided.
/// </summary>
/// <param name="locationUri">The location at which the status of requested content can be monitored.</param>
/// <param name="value">The value to format in the entity body.</param>
public AcceptedResult(Uri locationUri, object? value)
: base(value, StatusCodes.Status202Accepted)
{
if (locationUri == null)
{
throw new ArgumentNullException(nameof(locationUri));
}

if (locationUri.IsAbsoluteUri)
{
Location = locationUri.AbsoluteUri;
}
else
{
Location = locationUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped);
}
}

/// <summary>
/// Gets or sets the location at which the status of the requested content can be monitored.
/// </summary>
public string? Location { get; set; }

/// <inheritdoc />
protected override void OnFormatting(HttpContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}

if (!string.IsNullOrEmpty(Location))
{
context.Response.Headers.Location = Location;
}
}
}
}
13 changes: 13 additions & 0 deletions src/Http/Http.Results/src/BadRequestObjectResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.AspNetCore.Http.Result
{
internal sealed class BadRequestObjectResult : ObjectResult
{
public BadRequestObjectResult(object? error)
: base(error, StatusCodes.Status400BadRequest)
{
}
}
}
12 changes: 12 additions & 0 deletions src/Http/Http.Results/src/BadRequestResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.AspNetCore.Http.Result
{
internal sealed class BadRequestResult : StatusCodeResult
{
public BadRequestResult() : base(StatusCodes.Status400BadRequest)
{
}
}
}
120 changes: 120 additions & 0 deletions src/Http/Http.Results/src/ChallengeResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Microsoft.AspNetCore.Http.Result
{
/// <summary>
/// An <see cref="IResult"/> that on execution invokes <see cref="M:HttpContext.ChallengeAsync"/>.
/// </summary>
internal sealed partial class ChallengeResult : IResult
{
/// <summary>
/// Initializes a new instance of <see cref="ChallengeResult"/>.
/// </summary>
public ChallengeResult()
: this(Array.Empty<string>())
{
}

/// <summary>
/// Initializes a new instance of <see cref="ChallengeResult"/> with the
/// specified authentication scheme.
/// </summary>
/// <param name="authenticationScheme">The authentication scheme to challenge.</param>
public ChallengeResult(string authenticationScheme)
: this(new[] { authenticationScheme })
{
}

/// <summary>
/// Initializes a new instance of <see cref="ChallengeResult"/> with the
/// specified authentication schemes.
/// </summary>
/// <param name="authenticationSchemes">The authentication schemes to challenge.</param>
public ChallengeResult(IList<string> authenticationSchemes)
: this(authenticationSchemes, properties: null)
{
}

/// <summary>
/// Initializes a new instance of <see cref="ChallengeResult"/> with the
/// specified <paramref name="properties"/>.
/// </summary>
/// <param name="properties"><see cref="AuthenticationProperties"/> used to perform the authentication
/// challenge.</param>
public ChallengeResult(AuthenticationProperties? properties)
: this(Array.Empty<string>(), properties)
{
}

/// <summary>
/// Initializes a new instance of <see cref="ChallengeResult"/> with the
/// specified authentication scheme and <paramref name="properties"/>.
/// </summary>
/// <param name="authenticationScheme">The authentication schemes to challenge.</param>
/// <param name="properties"><see cref="AuthenticationProperties"/> used to perform the authentication
/// challenge.</param>
public ChallengeResult(string authenticationScheme, AuthenticationProperties? properties)
: this(new[] { authenticationScheme }, properties)
{
}

/// <summary>
/// Initializes a new instance of <see cref="ChallengeResult"/> with the
/// specified authentication schemes and <paramref name="properties"/>.
/// </summary>
/// <param name="authenticationSchemes">The authentication scheme to challenge.</param>
/// <param name="properties"><see cref="AuthenticationProperties"/> used to perform the authentication
/// challenge.</param>
public ChallengeResult(IList<string> authenticationSchemes, AuthenticationProperties? properties)
{
AuthenticationSchemes = authenticationSchemes;
Properties = properties;
}

public IList<string> AuthenticationSchemes { get; init; } = Array.Empty<string>();

public AuthenticationProperties? Properties { get; init; }

public async Task ExecuteAsync(HttpContext httpContext)
{
var logger = httpContext.RequestServices.GetRequiredService<ILogger<ChallengeResult>>();

Log.ChallengeResultExecuting(logger, AuthenticationSchemes);

if (AuthenticationSchemes != null && AuthenticationSchemes.Count > 0)
{
foreach (var scheme in AuthenticationSchemes)
{
await httpContext.ChallengeAsync(scheme, Properties);
}
}
else
{
await httpContext.ChallengeAsync(Properties);
}
}

private static partial class Log
{
public static void ChallengeResultExecuting(ILogger logger, IList<string> authenticationSchemes)
{
if (logger.IsEnabled(LogLevel.Information))
{
ChallengeResultExecuting(logger, authenticationSchemes.ToArray());
}
}

[LoggerMessage(1, LogLevel.Information, "Executing ChallengeResult with authentication schemes ({Schemes}).", EventName = "ChallengeResultExecuting", SkipEnabledCheck = true)]
private static partial void ChallengeResultExecuting(ILogger logger, string[] schemes);
}
}
}
13 changes: 13 additions & 0 deletions src/Http/Http.Results/src/ConflictObjectResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.AspNetCore.Http.Result
{
internal sealed class ConflictObjectResult : ObjectResult
{
public ConflictObjectResult(object? error) :
base(error, StatusCodes.Status409Conflict)
{
}
}
}
Loading

0 comments on commit b9efadc

Please sign in to comment.