Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Commit 3871260

Browse files
committed
Design extensibility for executors
We have all of these executors but they aren't really documented/supported for extensibility today. This change introduces a pattern for action result executors so we can make them extensible.
1 parent 5d1603c commit 3871260

File tree

63 files changed

+473
-178
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+473
-178
lines changed

src/Microsoft.AspNetCore.Mvc.Core/ContentResult.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore.Mvc.Infrastructure;
67
using Microsoft.AspNetCore.Mvc.Internal;
78
using Microsoft.Extensions.DependencyInjection;
89

@@ -32,7 +33,7 @@ public override Task ExecuteResultAsync(ActionContext context)
3233
throw new ArgumentNullException(nameof(context));
3334
}
3435

35-
var executor = context.HttpContext.RequestServices.GetRequiredService<ContentResultExecutor>();
36+
var executor = context.HttpContext.RequestServices.GetRequiredService<IActionResultExecutor<ContentResult>>();
3637
return executor.ExecuteAsync(context, this);
3738
}
3839
}

src/Microsoft.AspNetCore.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -250,17 +250,17 @@ internal static void AddMvcCoreServices(IServiceCollection services)
250250
services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>();
251251
services.TryAddSingleton(ArrayPool<byte>.Shared);
252252
services.TryAddSingleton(ArrayPool<char>.Shared);
253-
services.TryAddSingleton<ObjectResultExecutor>();
254-
services.TryAddSingleton<PhysicalFileResultExecutor>();
255-
services.TryAddSingleton<VirtualFileResultExecutor>();
256-
services.TryAddSingleton<FileStreamResultExecutor>();
257-
services.TryAddSingleton<FileContentResultExecutor>();
258-
services.TryAddSingleton<RedirectResultExecutor>();
259-
services.TryAddSingleton<LocalRedirectResultExecutor>();
260-
services.TryAddSingleton<RedirectToActionResultExecutor>();
261-
services.TryAddSingleton<RedirectToRouteResultExecutor>();
262-
services.TryAddSingleton<RedirectToPageResultExecutor>();
263-
services.TryAddSingleton<ContentResultExecutor>();
253+
services.TryAddSingleton<IActionResultExecutor<ObjectResult>, ObjectResultExecutor>();
254+
services.TryAddSingleton<IActionResultExecutor<PhysicalFileResult>, PhysicalFileResultExecutor>();
255+
services.TryAddSingleton<IActionResultExecutor<VirtualFileResult>, VirtualFileResultExecutor>();
256+
services.TryAddSingleton<IActionResultExecutor<FileStreamResult>, FileStreamResultExecutor>();
257+
services.TryAddSingleton<IActionResultExecutor<FileContentResult>, FileContentResultExecutor>();
258+
services.TryAddSingleton<IActionResultExecutor<RedirectResult>, RedirectResultExecutor>();
259+
services.TryAddSingleton<IActionResultExecutor<LocalRedirectResult>, LocalRedirectResultExecutor>();
260+
services.TryAddSingleton<IActionResultExecutor<RedirectToActionResult>, RedirectToActionResultExecutor>();
261+
services.TryAddSingleton<IActionResultExecutor<RedirectToRouteResult>, RedirectToRouteResultExecutor>();
262+
services.TryAddSingleton<IActionResultExecutor<RedirectToPageResult>, RedirectToPageResultExecutor>();
263+
services.TryAddSingleton<IActionResultExecutor<ContentResult>, ContentResultExecutor>();
264264

265265
//
266266
// Route Handlers

src/Microsoft.AspNetCore.Mvc.Core/FileContentResult.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore.Mvc.Infrastructure;
67
using Microsoft.AspNetCore.Mvc.Internal;
78
using Microsoft.Extensions.DependencyInjection;
89
using Microsoft.Net.Http.Headers;
@@ -76,7 +77,7 @@ public override Task ExecuteResultAsync(ActionContext context)
7677
throw new ArgumentNullException(nameof(context));
7778
}
7879

79-
var executor = context.HttpContext.RequestServices.GetRequiredService<FileContentResultExecutor>();
80+
var executor = context.HttpContext.RequestServices.GetRequiredService<IActionResultExecutor<FileContentResult>>();
8081
return executor.ExecuteAsync(context, this);
8182
}
8283
}

src/Microsoft.AspNetCore.Mvc.Core/FileStreamResult.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.IO;
66
using System.Threading.Tasks;
7+
using Microsoft.AspNetCore.Mvc.Infrastructure;
78
using Microsoft.AspNetCore.Mvc.Internal;
89
using Microsoft.Extensions.DependencyInjection;
910
using Microsoft.Net.Http.Headers;
@@ -73,7 +74,7 @@ public override Task ExecuteResultAsync(ActionContext context)
7374
throw new ArgumentNullException(nameof(context));
7475
}
7576

76-
var executor = context.HttpContext.RequestServices.GetRequiredService<FileStreamResultExecutor>();
77+
var executor = context.HttpContext.RequestServices.GetRequiredService<IActionResultExecutor<FileStreamResult>>();
7778
return executor.ExecuteAsync(context, this);
7879
}
7980
}

src/Microsoft.AspNetCore.Mvc.Core/Internal/ContentResultExecutor.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/ContentResultExecutor.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
using System;
55
using System.Text;
66
using System.Threading.Tasks;
7+
using Microsoft.AspNetCore.Mvc.Internal;
78
using Microsoft.Extensions.Logging;
89

9-
namespace Microsoft.AspNetCore.Mvc.Internal
10+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1011
{
11-
public class ContentResultExecutor
12+
public class ContentResultExecutor : IActionResultExecutor<ContentResult>
1213
{
1314
private const string DefaultContentType = "text/plain; charset=utf-8";
1415
private readonly ILogger<ContentResultExecutor> _logger;
@@ -20,6 +21,7 @@ public ContentResultExecutor(ILogger<ContentResultExecutor> logger, IHttpRespons
2021
_httpResponseStreamWriterFactory = httpResponseStreamWriterFactory;
2122
}
2223

24+
/// <inheritdoc />
2325
public virtual async Task ExecuteAsync(ActionContext context, ContentResult result)
2426
{
2527
if (context == null)

src/Microsoft.AspNetCore.Mvc.Core/Internal/FileContentResultExecutor.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileContentResultExecutor.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77
using Microsoft.Extensions.Logging;
88
using Microsoft.Net.Http.Headers;
99

10-
namespace Microsoft.AspNetCore.Mvc.Internal
10+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1111
{
12-
public class FileContentResultExecutor : FileResultExecutorBase
12+
public class FileContentResultExecutor : FileResultExecutorBase, IActionResultExecutor<FileContentResult>
1313
{
1414
public FileContentResultExecutor(ILoggerFactory loggerFactory)
1515
: base(CreateLogger<FileContentResultExecutor>(loggerFactory))
1616
{
1717
}
1818

19+
/// <inheritdoc />
1920
public virtual Task ExecuteAsync(ActionContext context, FileContentResult result)
2021
{
2122
if (context == null)

src/Microsoft.AspNetCore.Mvc.Core/Internal/FileResultExecutorBase.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
using Microsoft.AspNetCore.Http.Extensions;
1111
using Microsoft.AspNetCore.Http.Headers;
1212
using Microsoft.AspNetCore.Internal;
13+
using Microsoft.AspNetCore.Mvc.Internal;
1314
using Microsoft.Extensions.Logging;
1415
using Microsoft.Net.Http.Headers;
1516

16-
namespace Microsoft.AspNetCore.Mvc.Internal
17+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1718
{
1819
public class FileResultExecutorBase
1920
{

src/Microsoft.AspNetCore.Mvc.Core/Internal/FileStreamResultExecutor.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileStreamResultExecutor.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
using Microsoft.Extensions.Logging;
77
using Microsoft.Net.Http.Headers;
88

9-
namespace Microsoft.AspNetCore.Mvc.Internal
9+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1010
{
11-
public class FileStreamResultExecutor : FileResultExecutorBase
11+
public class FileStreamResultExecutor : FileResultExecutorBase, IActionResultExecutor<FileStreamResult>
1212
{
1313
public FileStreamResultExecutor(ILoggerFactory loggerFactory)
1414
: base(CreateLogger<FileStreamResultExecutor>(loggerFactory))
1515
{
1616
}
1717

18+
/// <inheritdoc />
1819
public virtual Task ExecuteAsync(ActionContext context, FileStreamResult result)
1920
{
2021
if (context == null)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Http;
6+
7+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
8+
{
9+
/// <summary>
10+
/// Defines an interface for a service which can execute a particular kind of <see cref="IActionResult"/> by
11+
/// manipulating the <see cref="HttpResponse"/>.
12+
/// </summary>
13+
/// <typeparam name="TResult">The type of <see cref="IActionResult"/>.</typeparam>
14+
/// <remarks>
15+
/// Implementions of <see cref="IActionResultExecutor{TResult}"/> are typically called by the
16+
/// <see cref="IActionResult.ExecuteResultAsync(ActionContext)"/> method of the corresponding action result type.
17+
/// Implementations should be registered as singleton services.
18+
/// </remarks>
19+
public interface IActionResultExecutor<in TResult> where TResult : IActionResult
20+
{
21+
/// <summary>
22+
/// Asynchronously excecutes the action result, by modifying the <see cref="HttpResponse"/>.
23+
/// </summary>
24+
/// <param name="context">The <see cref="ActionContext"/> associated with the current request."/></param>
25+
/// <param name="result">The action result to execute.</param>
26+
/// <returns>A <see cref="Task"/> which represents the asynchronous operation.</returns>
27+
Task ExecuteAsync(ActionContext context, TResult result);
28+
}
29+
}

src/Microsoft.AspNetCore.Mvc.Core/Internal/LocalRedirectResultExecutor.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/LocalRedirectResultExecutor.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Threading.Tasks;
56
using Microsoft.AspNetCore.Http;
67
using Microsoft.AspNetCore.Mvc.Core;
8+
using Microsoft.AspNetCore.Mvc.Internal;
79
using Microsoft.AspNetCore.Mvc.Routing;
810
using Microsoft.Extensions.Logging;
911
using Microsoft.Net.Http.Headers;
1012

11-
namespace Microsoft.AspNetCore.Mvc.Internal
13+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1214
{
13-
public class LocalRedirectResultExecutor
15+
public class LocalRedirectResultExecutor : IActionResultExecutor<LocalRedirectResult>
1416
{
1517
private readonly ILogger _logger;
1618
private readonly IUrlHelperFactory _urlHelperFactory;
@@ -31,7 +33,8 @@ public LocalRedirectResultExecutor(ILoggerFactory loggerFactory, IUrlHelperFacto
3133
_urlHelperFactory = urlHelperFactory;
3234
}
3335

34-
public virtual void Execute(ActionContext context, LocalRedirectResult result)
36+
/// <inheritdoc />
37+
public virtual Task ExecuteAsync(ActionContext context, LocalRedirectResult result)
3538
{
3639
if (context == null)
3740
{
@@ -64,6 +67,8 @@ public virtual void Execute(ActionContext context, LocalRedirectResult result)
6467
{
6568
context.HttpContext.Response.Redirect(destinationUrl, result.Permanent);
6669
}
70+
71+
return Task.CompletedTask;
6772
}
6873
}
6974
}

src/Microsoft.AspNetCore.Mvc.Core/Internal/ObjectResultExecutor.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/ObjectResultExecutor.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,18 @@
1111
using Microsoft.AspNetCore.Mvc.Core;
1212
using Microsoft.AspNetCore.Mvc.Formatters;
1313
using Microsoft.AspNetCore.Mvc.Formatters.Internal;
14+
using Microsoft.AspNetCore.Mvc.Internal;
1415
using Microsoft.Extensions.Logging;
1516
using Microsoft.Extensions.Options;
1617
using Microsoft.Extensions.Primitives;
1718
using Microsoft.Net.Http.Headers;
1819

19-
namespace Microsoft.AspNetCore.Mvc.Internal
20+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
2021
{
2122
/// <summary>
2223
/// Executes an <see cref="ObjectResult"/> to write to the response.
2324
/// </summary>
24-
public class ObjectResultExecutor
25+
public class ObjectResultExecutor : IActionResultExecutor<ObjectResult>
2526
{
2627
/// <summary>
2728
/// Creates a new <see cref="ObjectResultExecutor"/>.

src/Microsoft.AspNetCore.Mvc.Core/Internal/PhysicalFileResultExecutor.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/PhysicalFileResultExecutor.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@
1010
using Microsoft.Extensions.Logging;
1111
using Microsoft.Net.Http.Headers;
1212

13-
namespace Microsoft.AspNetCore.Mvc.Internal
13+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1414
{
15-
public class PhysicalFileResultExecutor : FileResultExecutorBase
15+
public class PhysicalFileResultExecutor : FileResultExecutorBase, IActionResultExecutor<PhysicalFileResult>
1616
{
1717
public PhysicalFileResultExecutor(ILoggerFactory loggerFactory)
1818
: base(CreateLogger<PhysicalFileResultExecutor>(loggerFactory))
1919
{
2020
}
2121

22+
/// <inheritdoc />
2223
public virtual Task ExecuteAsync(ActionContext context, PhysicalFileResult result)
2324
{
2425
if (context == null)

src/Microsoft.AspNetCore.Mvc.Core/Internal/RedirectResultExecutor.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/RedirectResultExecutor.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Threading.Tasks;
56
using Microsoft.AspNetCore.Http;
7+
using Microsoft.AspNetCore.Mvc.Internal;
68
using Microsoft.AspNetCore.Mvc.Routing;
79
using Microsoft.Extensions.Logging;
810
using Microsoft.Net.Http.Headers;
911

10-
namespace Microsoft.AspNetCore.Mvc.Internal
12+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1113
{
12-
public class RedirectResultExecutor
14+
public class RedirectResultExecutor : IActionResultExecutor<RedirectResult>
1315
{
1416
private readonly ILogger _logger;
1517
private readonly IUrlHelperFactory _urlHelperFactory;
@@ -30,7 +32,8 @@ public RedirectResultExecutor(ILoggerFactory loggerFactory, IUrlHelperFactory ur
3032
_urlHelperFactory = urlHelperFactory;
3133
}
3234

33-
public virtual void Execute(ActionContext context, RedirectResult result)
35+
/// <inheritdoc />
36+
public virtual Task ExecuteAsync(ActionContext context, RedirectResult result)
3437
{
3538
if (context == null)
3639
{
@@ -63,6 +66,8 @@ public virtual void Execute(ActionContext context, RedirectResult result)
6366
{
6467
context.HttpContext.Response.Redirect(destinationUrl, result.Permanent);
6568
}
69+
70+
return Task.CompletedTask;
6671
}
6772
}
6873
}

src/Microsoft.AspNetCore.Mvc.Core/Internal/RedirectToActionResultExecutor.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/RedirectToActionResultExecutor.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Threading.Tasks;
56
using Microsoft.AspNetCore.Http;
67
using Microsoft.AspNetCore.Mvc.Core;
8+
using Microsoft.AspNetCore.Mvc.Internal;
79
using Microsoft.AspNetCore.Mvc.Routing;
810
using Microsoft.Extensions.Logging;
911
using Microsoft.Net.Http.Headers;
1012

11-
namespace Microsoft.AspNetCore.Mvc.Internal
13+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1214
{
13-
public class RedirectToActionResultExecutor
15+
public class RedirectToActionResultExecutor : IActionResultExecutor<RedirectToActionResult>
1416
{
1517
private readonly ILogger _logger;
1618
private readonly IUrlHelperFactory _urlHelperFactory;
@@ -31,7 +33,8 @@ public RedirectToActionResultExecutor(ILoggerFactory loggerFactory, IUrlHelperFa
3133
_urlHelperFactory = urlHelperFactory;
3234
}
3335

34-
public virtual void Execute(ActionContext context, RedirectToActionResult result)
36+
/// <inheritdoc />
37+
public virtual Task ExecuteAsync(ActionContext context, RedirectToActionResult result)
3538
{
3639
if (context == null)
3740
{
@@ -69,6 +72,8 @@ public virtual void Execute(ActionContext context, RedirectToActionResult result
6972
{
7073
context.HttpContext.Response.Redirect(destinationUrl, result.Permanent);
7174
}
75+
76+
return Task.CompletedTask;
7277
}
7378
}
7479
}

src/Microsoft.AspNetCore.Mvc.Core/Internal/RedirectToPageResultExecutor.cs renamed to src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/RedirectToPageResultExecutor.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Threading.Tasks;
56
using Microsoft.AspNetCore.Http;
67
using Microsoft.AspNetCore.Mvc.Core;
8+
using Microsoft.AspNetCore.Mvc.Internal;
79
using Microsoft.AspNetCore.Mvc.Routing;
810
using Microsoft.Extensions.Logging;
911
using Microsoft.Net.Http.Headers;
1012

11-
namespace Microsoft.AspNetCore.Mvc.Internal
13+
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1214
{
13-
public class RedirectToPageResultExecutor
15+
public class RedirectToPageResultExecutor : IActionResultExecutor<RedirectToPageResult>
1416
{
1517
private readonly ILogger _logger;
1618
private readonly IUrlHelperFactory _urlHelperFactory;
@@ -31,7 +33,8 @@ public RedirectToPageResultExecutor(ILoggerFactory loggerFactory, IUrlHelperFact
3133
_urlHelperFactory = urlHelperFactory;
3234
}
3335

34-
public virtual void Execute(ActionContext context, RedirectToPageResult result)
36+
/// <inheritdoc />
37+
public virtual Task ExecuteAsync(ActionContext context, RedirectToPageResult result)
3538
{
3639
if (context == null)
3740
{
@@ -69,6 +72,8 @@ public virtual void Execute(ActionContext context, RedirectToPageResult result)
6972
{
7073
context.HttpContext.Response.Redirect(destinationUrl, result.Permanent);
7174
}
75+
76+
return Task.CompletedTask;
7277
}
7378
}
7479
}

0 commit comments

Comments
 (0)