56

I need to add a couple of await functions in ConfigureServices in Startup.cs and am running into an issue.

System.InvalidOperationException Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddMvc()' inside the call to 'IApplicationBuilder.ConfigureServices(...)' or 'IApplicationBuilder.UseMvc(...)' in the application startup code.

As seen by the code below, AddMvc & UseMvc are in their correct locations, however, I still get this error.

public async void ConfigureServices(IServiceCollection services)
{
    ...
    await manager.Initialize();
    var data = await manager.GetData();
    ...
    services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerFactory)
{
    ...
    app.UseMvc();
    ....
}

Is it possible to make ConfigureServices an async function?

1

2 Answers 2

63

No, you can't. Doing that would result in a race condition.

Instead, consider making your operation synchronous or using .Wait()/.Result (depending on whether the async method returns data or not) to block until the asynchronous task completes.

Sign up to request clarification or add additional context in comments.

7 Comments

Can you explain why does the race condition occur? A bit more depth here with better understanding of what's executing when would be terrific.
Please add some explanation about the "race condition"
@MaviDomates, @Vencovsky, the race condition occurs because the underlying code within the ConfigureServices of IHostBuilder continues to process the remainder of the host startup without awaiting your specific async implementation. This is because ConfigureServices accepts an Action delegate which returns no Task or anything that's awaitable. As far as the builder is concerned it has executed your method and done its job.
Pretty sure GetAwaiter() just wraps the task in an awaiter and GetResult() on the awaiter just calls the Result property which will call Wait() on the task if it isn't finished... The only real benefit is how exception propagate. GetAwaiter() isn't actually intended for you to use (ref: learn.microsoft.com/en-us/dotnet/api/…)
This also appears to be netcore web application/api. I'm fairly certain deadlocks are of no concern here because there's no context.
|
2

If you just need to perform asynchronous actions on the services from the ServiceProvider before starting the application, then there is a simple way to do it using the HostInitActions nuget

    public void ConfigureServices(IServiceCollection services)
    {       
        services.AddSingleton<IService, MyService>();

        services.AddAsyncServiceInitialization()
            .AddInitAction<IService>(async (service) =>
            {
                await service.InitAsync();
            });
    }

This nugget ensures that your initialization action will be performed asynchronously before the application starts but right after the ServiceProvider is built, so the services are already available using dependency injection. These asynchronous operations can have multiple services as input, and thanks to this, they can also cooperate and share the data they obtained as part of this asynchronous action. Just look at the nuget documentation.

Another advantage of this approach is that this initialization action can be defined from any place where services are installed into the IServiceCollection (For example, in an extension method in another project that installs internal implementations of public interfaces). This means that the ASP.NET Core project does not need to know what service and how it should be initialized, and it will still be done.

1 Comment

This seems to be build on top of Microsoft.Extensions.Hosting, which basically just calls StartAsync().GetAwaiter().GetResult(). It's cleaner in that it adds centralization, but it's still a bit cheaty.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.