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

Unable to inject reusable ConfigurationClient per recommendation of SDK guide. #380

Closed
goldsam opened this issue Feb 9, 2023 · 20 comments · Fixed by #598
Closed

Unable to inject reusable ConfigurationClient per recommendation of SDK guide. #380

goldsam opened this issue Feb 9, 2023 · 20 comments · Fixed by #598
Assignees

Comments

@goldsam
Copy link

goldsam commented Feb 9, 2023

The SDK Guide, recommends reusing your ConfigurationClient, however the APIs of this library prevent this by disallowing injection of a custom ConfigurationClient instance. The library creates a new instance of ConfigurationClient for each call to ConfigurationBuilder.AddAzureAppConfiguration, which is unduly restrictive.

@zhenlan
Copy link
Contributor

zhenlan commented Feb 13, 2023

When ConfigurationBuilder.AddAzureAppConfiguration is called more than once, do you connect to the same App Configuration store or different stores?

@goldsam
Copy link
Author

goldsam commented Feb 14, 2023

I'm working on a multi-tenanted project where a distinct IConfiguration (and thus ConfigurationBuilder) is created and cached for each tenant. Depending on the environment and tenant, ConfigurationBuilder.AddAzureAppConfiguration is sometimes called passing the same ConfigurationClient instance but using different label filters.

With all due respect, I believe the response to your question is irrelevant, as a user should be able to specify whatever ClientConfiguration instance they please. Forcing a very specific mechanism for constructing the underlying ConfigurationClient (as apposed to allowing it to be injected) violates software design best practices and principles.

@goldsam
Copy link
Author

goldsam commented May 19, 2023

@zhenlan Had time to look at this? My PR went stale. Is it going to be ignored again if I update it?

@goldsam
Copy link
Author

goldsam commented Dec 5, 2023

Hello?! @amerjusupovic Can you give this some love?

@amerjusupovic
Copy link
Member

Hi @goldsam, I'm sorry about the delayed response here. I think this looks like a valid point from the blog you linked and related issues I found. Right now, I'm just getting more context on this from the team to see if there was a reason for omitting that capability. If not, then I'll get back to you about the PR, but I'm working on it!

@goldsam
Copy link
Author

goldsam commented Dec 9, 2023

@amerjusupovic Thank you. I had actually submitted a PR which now has I conflicts. I would be happed to update it if you are willing to give it some attention afterwards. If you would review my PR and provide feedback, I would be happy to do the work to get this ready. Just let me know. Thank you very much.

@goldsam
Copy link
Author

goldsam commented Dec 29, 2023

@amerjusupovic Did you see that I had created a PR previously?

@amerjusupovic
Copy link
Member

@goldsam I saw your PR but from what I gathered so far from others, it's unfortunately not the way we want to implement this. We're keeping this in mind as a future improvement, but for now it's not supported.

@carlin-q-scott
Copy link

@amerjusupovic As an alternative to @goldsam 's PR, could the options class be modified to make the client setter public so that we can inject the client ourselves? It's a smaller change and allows us users to decide what to do.

@goldsam
Copy link
Author

goldsam commented Jun 9, 2024

@zhenlan @amerjusupovic @zhiyuanliang-ms You guys are killing me. Please add support to customize the creation and lifetime of the client. I think this is a fairly basic capability.

I created a working PR which you rejected without any justification beyond" that's not what we want to do". @carlin-q-scott also offered a simple, straightforward solution which you completely ignored. It's been well over a year.

Time to up your game and be better open source denizens.

@amerjusupovic
Copy link
Member

Because of geo-replication support, the provider creates ConfigurationClient instances as needed by discovering any replicas in App Configuration. I think it could be confusing to be able to pass in a ConfigurationClient while the provider is still creating clients behind the scenes, since they may be used in case of failover, like if an App Configuration endpoint can't be reached and the provider tries to connect to a replica instead.

Here's another option that might fit the current provider usage:

.AddAzureAppConfiguration(o =>
{
    o.Connect(new Uri("https://foo.azconfig.io"), new MyConfigurationClientFactory());
});
class MyConfigurationClientFactory : IConfigurationClientFactory
{
    public ConfigurationClient CreateClient(string endpoint) 
    {
        ...
    }
}
interface IConfigurationClientFactory
{
    ConfigurationClient CreateClient(string endpoint);
}

The IConfigurationClientFactory interface has a CreateClient method that the provider would call whenever it needs to get a ConfigurationClient for a specific endpoint. By default, the provider would have an implementation that behaves the same as it does today where it simply creates a new client. However, a user could pass in their own implemented factory instead where the CreateClient method returns an existing ConfigurationClient.

Of course, it's only a suggestion but just want to throw this out there.

@zhenlan @drago-draganov @jimmyca15

@drago-draganov
Copy link
Contributor

drago-draganov commented Jun 11, 2024

Azure SDK client DI flow may be able to help here.

@goldsam
Copy link
Author

goldsam commented Jun 11, 2024

@drago-draganov I don't think I understand what you're referencing. This library doesn't support inject of the client like most other Azure libraries do. That is another aspect of this issue.

To be clear, this is not respected by this library:

builder.Services.AddAzureClients(clientBuilder =>
{
   clientBuilder.AddConfigurationClient(...);
});

@drago-draganov
Copy link
Contributor

drago-draganov commented Jun 11, 2024

@goldsam
Sorry, I wasn't specific. My reference was that AppConfigProvider should add support for Azure SDK client DI, instead of custom factory or else (I saw a few proposals mentioned). That, I thought, will enable the scenario you asked for.
Perhaps naming the clients needs level of conformance (ex. endpoint/connection_string as client name), but that's details.

Appreciate your feedback!

@goldsam
Copy link
Author

goldsam commented Jun 12, 2024

@drago-draganov I think we are in agreement😉 Supporting Azure SDK client DI would suffice for my needs just fine. Its unclear to me how this would work while maintaining backwards API compatibility. I think regardless of the solution, additions be necessary to class AzureAppConfigurationOptions.

@drago-draganov
Copy link
Contributor

I am not sure that we need changes in AzureAppConfigurationOptions. Perhaps, if we try IAzureClientFactory, it may be OK.

@amerjusupovic
Copy link
Member

Just an update: we're looking into using the SDK DI pattern as mentioned, but as far as I know we don't have access to DI from the provider. I'm reaching out to some people who are involved with the SDK to see if they have any suggestions or alternative ways to get access to clients added this way.

@amerjusupovic
Copy link
Member

After discussion with the SDK team, it sounds like it would be difficult to unify the approach to add ConfigurationClient instances to the provider with the SDK's AddAzureClients API. Our next step is likely allowing users to pass in a client factory to the AddAzureAppConfiguration options once we finalize that design.

@amerjusupovic
Copy link
Member

The design we plan to implement at the moment is adding:

AzureAppConfigurationOptions.SetClientFactory(IAzureClientFactory<ConfigurationClient> factory)

The provider would call CreateClient on the factory whenever it needs a client for a given endpoint or connection string. If the API is called, no clients will be created by the provider.

@samsadsam
Copy link
Contributor

@goldsam PR is merged. It'll be included in the next release.

Closing this :)

@github-project-automation github-project-automation bot moved this from 👀 In Review to Done in AppConfiguration-DotnetProvider Oct 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment