Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Startup Async Configure #14801

Merged
merged 8 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
Expand Down Expand Up @@ -41,12 +41,12 @@ public override void ConfigureServices(IServiceCollection services)
}

/// <inheritdocs />
public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
public override async ValueTask ConfigureAsync(IApplicationBuilder app, IServiceProvider serviceProvider)
{
var localizationService = serviceProvider.GetService<ILocalizationService>();

var defaultCulture = localizationService.GetDefaultCultureAsync().GetAwaiter().GetResult();
var supportedCultures = localizationService.GetSupportedCulturesAsync().GetAwaiter().GetResult();
var defaultCulture = await localizationService.GetDefaultCultureAsync();
var supportedCultures = await localizationService.GetSupportedCulturesAsync();

var localizationOptions = serviceProvider.GetService<IOptions<RequestLocalizationOptions>>().Value;
var ignoreSystemSettings = serviceProvider.GetService<IOptions<CultureOptions>>().Value.IgnoreSystemSettings;
Expand Down
20 changes: 20 additions & 0 deletions src/OrchardCore/OrchardCore.Abstractions/Modules/IAsyncStartup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;

namespace OrchardCore.Modules
{
/// <summary>
/// An implementation of this interface allows to configure asynchronously the tenant pipeline.
/// </summary>
public interface IAsyncStartup
{
/// <summary>
/// This method gets called before any <see cref="IStartup.Configure"/> and can collaborate to
/// build the tenant pipeline, but is not intended to configure the route/endpoint middleware.
/// </summary>
/// <param name="builder"></param>
/// <param name="serviceProvider"></param>
ValueTask ConfigureAsync(IApplicationBuilder builder, IServiceProvider serviceProvider);
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

namespace OrchardCore.Modules
{
public abstract class StartupBase : IStartup
public abstract class StartupBase : IStartup, IAsyncStartup
{
/// <inheritdoc />
public virtual int Order { get; } = 0;
Expand All @@ -22,5 +23,8 @@ public virtual void ConfigureServices(IServiceCollection services)
public virtual void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
{
}

/// <inheritdoc />
public virtual ValueTask ConfigureAsync(IApplicationBuilder app, IServiceProvider serviceProvider) => default;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static async Task BuildPipelineAsync(this ShellContext context)
{
if (!context.HasPipeline())
{
context.Pipeline = context.BuildPipeline();
context.Pipeline = await context.BuildPipelineInternalAsync();
}
}
finally
Expand All @@ -43,22 +43,20 @@ public static async Task BuildPipelineAsync(this ShellContext context)
/// <summary>
/// Builds the tenant pipeline.
/// </summary>
private static IShellPipeline BuildPipeline(this ShellContext context)
private static async ValueTask<IShellPipeline> BuildPipelineInternalAsync(this ShellContext context)
{
var features = context.ServiceProvider.GetService<IServer>()?.Features;
var builder = new ApplicationBuilder(context.ServiceProvider, features ?? new FeatureCollection());
var startupFilters = builder.ApplicationServices.GetService<IEnumerable<IStartupFilter>>();

Action<IApplicationBuilder> configure = builder =>
{
ConfigurePipeline(builder);
};

Action<IApplicationBuilder> configure = builder => { };
foreach (var filter in startupFilters.Reverse())
{
configure = filter.Configure(configure);
}

await ConfigurePipelineAsync(builder);

configure(builder);

var shellPipeline = new ShellRequestPipeline
Expand All @@ -72,13 +70,21 @@ private static IShellPipeline BuildPipeline(this ShellContext context)
/// <summary>
/// Configures the tenant pipeline.
/// </summary>
private static void ConfigurePipeline(IApplicationBuilder builder)
private static async ValueTask ConfigurePipelineAsync(IApplicationBuilder builder)
{
// 'IStartup' instances are ordered by module dependencies with a 'ConfigureOrder' of 0 by default.
// 'OrderBy' performs a stable sort, so the order is preserved among equal 'ConfigureOrder' values.
var startups = builder.ApplicationServices.GetServices<IStartup>().OrderBy(s => s.ConfigureOrder);

var services = ShellScope.Services;
foreach (var startup in startups)
{
if (startup is IAsyncStartup asyncStartup)
{
await asyncStartup.ConfigureAsync(builder, services);
}
}

builder.UseRouting().UseEndpoints(routes =>
{
foreach (var startup in startups)
Expand Down