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

Why doesn't IConfigurationProvider have an async Load method? #36018

Open
mariusGundersen opened this issue Nov 28, 2019 · 25 comments
Open

Why doesn't IConfigurationProvider have an async Load method? #36018

mariusGundersen opened this issue Nov 28, 2019 · 25 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-Extensions-Configuration feature-request
Milestone

Comments

@mariusGundersen
Copy link
Contributor

This might be a small or silly thing to ask about/for, but why isn't IConfigurationProvider.Load() async, returning a Task? Most configuration loading is going to be async, for example getting something from the filesystem or from the network. Now implementors are forced to use GetAwaiter().GetResult() in this method.

@analogrelay
Copy link
Contributor

Honestly, it was probably just an oversight. You are correct that many providers do I/O. Most providers currently do this by doing the I/O synchronously.

I'll put this in the backlog, but it's a fairly high-cost change since it would be extremely viral. It would mean adding ConfigurationBuilder.BuildAsync, which would again propagate up to the callers.

@analogrelay analogrelay transferred this issue from dotnet/extensions May 7, 2020
@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this issue. Please help me learn by adding exactly one area label.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label May 7, 2020
@analogrelay analogrelay added this to the Future milestone May 7, 2020
@maryamariyan maryamariyan removed the untriaged New issue has not been triaged by the area owner label Jul 1, 2020
@maryamariyan maryamariyan added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Oct 1, 2020
@maryamariyan
Copy link
Member

maryamariyan commented Oct 1, 2020

@mariusGundersen thanks for the issue. The best next step on this would be to prepare the API proposal, usage, etc. in the issue page here (following https://github.com/dotnet/runtime/blob/master/docs/project/api-review-process.md).

@dkogithub
Copy link

Hi all, any progress on that?
We are working on our async application improvements and it would be super cool to have it async as well :)

@maryamariyan
Copy link
Member

@DkozhevnikovConfigit do you have some usage examples in mind to help shape the API?

@dkogithub
Copy link

dkogithub commented Mar 26, 2021

@maryamariyan it's really simple example.
We are storing our configuration within the DB, so when we want to load it in async manner we call GetAwaiter().GerResult() in Load and TryGet methods.

public class OurConfigurationProvider : ConfigurationProvider
{
    public override void Load()
    {
      Data = _db.GetConfigurationsAsync().GetAwaiter().GerResult();
    }

    public override bool TryGet(string key, out string value)
    {
      if (!Data.Contains(key))
      {
        var configuration = _db.GetConfigurationAsync(key).GetAwaiter().GerResult();
        if (configuration != null)
        {
          Data[key] = configuration;
        }
      }
        
      value = Data[key];
      return true;
    }
}

so it would be cool to do it async like:

    public class OurConfigurationProvider : ConfigurationProvider
    {
      public override async Task LoadAsync()
      {
        Data = await _db.GetConfigurationsAsync();
      }

      public override async Task<string> GetAsync(string key)
      {
        if (!Data.ContainsKey(key))
        {
          var configuration = await _db.GetConfigurationAsync(key);
          if (configuration != null)
          {
            Data[key] = configuration;
          }
          else
          {
            return null;
          }
        }
        return Data[key];
      }
    }

@eduardgrinberg
Copy link

Hi, any update on this?

We are missing this option as well. We're loading configuraition from http endpoint and would be really nice if we could use async here.

Thanks

@JasonBock
Copy link

FWIW I just ran into this with internal code at my employer. I also would like to see this have async APIs.

@KieranDevvs
Copy link

KieranDevvs commented Nov 21, 2022

This really needs to be added. I'm loading a large configuration from a database, its not nice having to force other async API's to run synchronously because the .NET has gaps where it doesn't support it.

@piekstra
Copy link

piekstra commented Dec 1, 2022

I've just encountered this as well - we want to have our appsettings.json use paths to secrets in AWS Secrets Manager - with a custom IConfigurationSource and ConfigurationProvider, we are able to resolve those paths to actual secrets but should be able to do so asynchronously.

@dominikjeske
Copy link

I also vote for this.

@eventpromo
Copy link

Yes, i'm waiting for this feature as well

@niyazz
Copy link

niyazz commented Mar 21, 2023

I agree with the comments above and also need that feature to get a configuration with a custom provider over HTTP calls.

@f135ta
Copy link

f135ta commented May 19, 2023

At least this ticket has only been open for 3.5 yrs.......

@MCKanpolat
Copy link

I'm using Vault for getting secrets via http so async implementation is very useful such this scenarios.

@dazinator
Copy link

dazinator commented Jun 24, 2023

I've implemented an async adaptor over here

I'll put this in the backlog, but it's a fairly high-cost change since it would be extremely viral. It would mean adding ConfigurationBuilder.BuildAsync, which would again propagate up to the callers.

It is possible to use an async provider without the virality, but you have to create an instance of the async provider first and call InitialiseAsync() on it to prefetch the initial values, prior to adding to ConfigurationBuilder. That way when ConfigurationBuilder.Build is called the provider can return its prefetched config synchronously. The other aspect is to write an async version of ChangeToken.OnChange -> this allows the provider to handle change token reloads asynchronously.

@stevo-knievo
Copy link

I have a similar scenario like @MCKanpolat. An async implementation would be really useful. Plus one for async!

@Edgaras91
Copy link

Does anyone know how I could safely fetch config asynchronously from TryGet override?

     public override bool TryGet(string key, out string value)
      {
          if (Data.ContainsKey(key))
          {
              //can't await? 
              FetchConfigAsync(key).RunSynchronously();
          }

          return base.TryGet(key, out value);
      }

@Rabadash8820
Copy link

Rabadash8820 commented Nov 10, 2023

@Edgaras91 You should probably open a separate Issue or ask your question on a Q&A site like StackOverflow. I'm not really sure what you're trying to do. FetchConfigAsync is already async, so there's no need to wrap it in another async call, and your additional Data.ContainsKey validation isn't actually doing anything as written. All that said, if you just declare TryGet async then you can use await.

@KieranDevvs
Copy link

@Edgaras91 You should probably open a separate Issue or ask your question on a Q&A site like StackOverflow. I'm not really sure what you're trying to do. FetchConfigAsync is already async, so there's no need to wrap it in another async call, and your additional Data.ContainsKey validation isn't actually doing anything as written. All that said, if you just declare TryGet async then you can use await.

You cant declare the overridden method as async because the return type would need to be Task or Task<T> which wouldn't match the virtual signature.

@Rabadash8820
Copy link

You cant declare the overridden method as async because the return type would need to be Task or Task which wouldn't match the virtual signature.

Good point. In that case, something like the following could work:

public override bool TryGet(string key, out string value)
{
    if (Data.ContainsKey(key))
    {
            value = FetchConfigAsync(key).Result;
            return true;
    }

    return base.TryGet(key, out value);
}

@Edgaras91
Copy link

Edgaras91 commented Nov 10, 2023 via email

@Rabadash8820
Copy link

@Edgaras91 How would callers get the desired value then? You either have to synchronously wait on the FetchConfigAsync task or use some kind of callback (which is what async/await is essentially doing under the hood). A workaround would probably be to use aggregation instead of inheritance. Then, you wouldn't be constrained by the TryGet signature of your base class and could instead have one that returns async Task<bool>.

But again, we are de-railing this GitHub Issue. I encourage you to open a separate Issue or StackOverflow question or you can DM me. I will not be discussing it further here and I encourage others to do the same.

@klemmchr
Copy link

What's the status of the issue? Almost every configuration provider is async in some way, so this would benefit a lot of providers. Even file providers should take advantage of an async provider.

Synchronously waiting for a Task result might be fine in a lot of scenarios (like ASP.NET) but is not possible for Blazor apps. This is a huge drawback if you want to load any remote configuration. Loading remote configurations is extremely common in client side apps, it's almost a must have.

@0xced
Copy link
Contributor

0xced commented Nov 10, 2023

There's already an API proposal for an async configuration provider: #79193

Maybe we could try to vote and comment over there to give it some momentum. 🤞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-Extensions-Configuration feature-request
Projects
None yet
Development

No branches or pull requests