Skip to content

Comments

Add comprehensive dependency injection support with IServiceCollection extension methods #696

Open
mokarchi wants to merge 14 commits intoopenai:mainfrom
mokarchi:main
Open

Add comprehensive dependency injection support with IServiceCollection extension methods #696
mokarchi wants to merge 14 commits intoopenai:mainfrom
mokarchi:main

Conversation

@mokarchi
Copy link

@mokarchi mokarchi commented Sep 18, 2025

This PR implements per-client configuration and dependency injection support for the OpenAI .NET library, fully aligning with the design proposed in issue #932 and following the modern .NET / Azure SDK pattern using System.ClientModel.

The new approach replaces manual DI registrations with strongly-typed, configuration-bound settings classes for each specialized client (ChatClient, EmbeddingClient, AudioClient, ImageClient, ModerationClient).

Key Features Added

  1. Dedicated Settings Classes per Client
    Each specialized client now has its own settings class inheriting from ClientSettings

    These classes contain only the properties needed by the client's primary constructor (mainly Model and Options), and credential is handled automatically by the base ClientSettings.

    Example structure:

    [Experimental("SCME0002")]
    public sealed class ChatClientSettings : ClientSettings
    {
        public string? Model { get; set; }
        public OpenAIClientOptions? Options { get; set; } = new();
        // BindCore implemented for configuration binding
    }
  2. New Constructor for Specialized Clients
    Each specialized client now has an additional constructor that accepts its settings class:

    [Experimental("SCME0002")]
    public ChatClient(ChatClientSettings settings)
     : this(settings.Model, AuthenticationPolicy.Create(settings), settings.Options ?? new OpenAIClientOptions())
    {
    }

(Similar constructors added to EmbeddingClient, AudioClient, ImageClient, ModerationClient)

  1. Fluent DI Registration via IHostApplicationBuilder
    Extension methods on IHostApplicationBuilder for registering each client with configuration support:
builder.AddChatClient("Chat")           // sectionName = "Chat"
builder.AddEmbeddingClient("Embedding");
builder.AddAudioClient("Audio");
builder.AddImageClient("Image");
builder.AddModerationClient("Moderation");

Keyed registration is also supported:

builder.AddKeyedChatClient("premium", "PremiumChat");
  1. Configuration Integration (appsettings.json)
    Full support for Microsoft.Extensions.Configuration binding with hierarchical keys, $ref syntax, and environment variables:
{
  "Chat": {
    "Model": "gpt-4o-mini",
    "Options": {
      "OrganizationId": "org-abc123",
      "ProjectId": "proj-xyz789"
    }
  },
  "Embedding": {
    "Model": "text-embedding-3-small"
  },
  "Audio": {
    "Model": "whisper-1"
  }
}

This commit introduces new features for dependency injection in the OpenAI .NET library, allowing for easier registration and configuration of clients within ASP.NET Core applications. Key changes include:

- New extension methods for registering OpenAI clients with support for `appsettings.json` and environment variables.
- Introduction of the `OpenAIServiceOptions` class for simplified configuration.
- Updates to README.md with detailed usage instructions and examples.
- Modifications to project files to include necessary package references.
- Comprehensive unit tests to validate the new features and ensure proper functionality.
@stephentoub
Copy link
Contributor

Should this instead be left to Aspire, e.g. https://www.nuget.org/packages/Aspire.OpenAI ?

cc: @eerhardt

@KrzysztofCwalina
Copy link
Collaborator

I also think configuration like this needs to be aligned with what we already have in both Aspire, .NET, and Azure. In fact, I had a sync up with @eerhardt a couple of days ago to design a consistent solution.

cc @m-nash

@mokarchi
Copy link
Author

@stephentoub @KrzysztofCwalina, I was wondering about the current status of this PR. Should I wait or make any changes?

@KrzysztofCwalina
Copy link
Collaborator

@stephentoub @KrzysztofCwalina, I was wondering about the current status of this PR. Should I wait or make any changes?

@m-nash @eerhardt, @jsquire, how would you want to handle this PR? It seems like you are working features similar to it.

@mokarchi
Copy link
Author

mokarchi commented Oct 1, 2025

@eerhardt Could you review this, please?

@jsquire
Copy link
Collaborator

jsquire commented Oct 1, 2025

Hi @mokarchi. Thank you for your contribution and your interest in improving the OpenAI developer experience. Apologies for the feedback delay, but there was some coordination needed on other workstreams. As Krzysztof mentioned, we are in the process of designing an experience where clients natively integrate with the .NET configuration, options, and DI systems. Part of that work entails defining the common patterns across the OpenAI clients for DI registration, construction, and configuration and ensuring that they align closely with the .NET ecosystem.

Because we don't yet have a fully codified design, we're not able to provide the detailed feedback that would be needed to help your contribution align. As a result, we're unable to move forward at this time. We have a couple of options that you can consider for next steps:

  • We can close this PR out and leave the implementation to the team once a design is settled.
  • We can close this PR out and coordinate on a new implementation together once the design is settled.
  • We can park this PR for now and then work together to align the implementation to the design once it is available.

Please let us know how you'd like to proceed.

//cc: @m-nash for awareness.

jsquire
jsquire previously requested changes Oct 1, 2025
Copy link
Collaborator

@jsquire jsquire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking for now to prevent accidental merge.

@mokarchi
Copy link
Author

mokarchi commented Oct 1, 2025

Thank you for the update, @jsquire.
I'd like to go with the third option: parking this PR for now and working together to align the implementation once the design is available. I'm happy to iterate on this contribution to ensure it fits seamlessly with the broader patterns you're defining.

@jsquire
Copy link
Collaborator

jsquire commented Oct 1, 2025

Thank you, @mokarchi. We appreciate your flexibility and understanding.

@jsquire jsquire requested a review from m-nash October 1, 2025 20:21
@m-nash
Copy link
Collaborator

m-nash commented Oct 1, 2025

Thank you for the update, @jsquire. I'd like to go with the third option: parking this PR for now and working together to align the implementation once the design is available. I'm happy to iterate on this contribution to ensure it fits seamlessly with the broader patterns you're defining.

Late to the party, but yeah this feels like the best path forward. Once the design is ready to share we can collaborate on the implementation.

@mokarchi mokarchi requested a review from christothes as a code owner February 5, 2026 11:22
…ests

- Deleted ServiceCollectionExtensionsAdvanced.cs which contained methods for adding OpenAI services with enhanced configuration support.
- Removed OpenAIServiceOptionsTests.cs that tested the OpenAIServiceOptions class.
- Deleted ServiceCollectionExtensionsAdvancedTests.cs which included tests for the advanced service collection methods.
- Updated ServiceCollectionExtensionsTests.cs to reflect changes in service registration methods and added new tests for the simplified client builder methods.
@mokarchi
Copy link
Author

mokarchi commented Feb 5, 2026

Hi @m-nash, @jsquire
I've applied the changes based on the design outlined in issue #932.
Would appreciate your review and any feedback or additional requirements.
Thanks for the guidance!

@m-nash
Copy link
Collaborator

m-nash commented Feb 7, 2026

Hi @m-nash, @jsquire I've applied the changes based on the design outlined in issue #932. Would appreciate your review and any feedback or additional requirements. Thanks for the guidance!

@mokarchi You jumped on this faster than I was ready I hadn't put all the details into the issue yet. I updated issues with the rest of the details.

@mokarchi
Copy link
Author

mokarchi commented Feb 7, 2026

Hi @m-nash, @jsquire I've applied the changes based on the design outlined in issue #932. Would appreciate your review and any feedback or additional requirements. Thanks for the guidance!

@mokarchi You jumped on this faster than I was ready I hadn't put all the details into the issue yet. I updated issues with the rest of the details.

Ready for your review. let me know if anything needs tweaking or if I missed a detail.
Appreciate your help!

Copy link
Collaborator

@m-nash m-nash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we are missing a few clients in here like AssistantClient, BatchClient, etc. Lets add those in as well with a settings that matches their main ctor.

Copy link
Collaborator

@m-nash m-nash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we are missing a few clients in here like AssistantClient, BatchClient, etc. Lets add those in as well with a settings that matches their main ctor.

Copy link
Collaborator

@m-nash m-nash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor update but this is looking good. @joseharriaga can you do a quick review as well?

@jsquire jsquire dismissed their stale review February 10, 2026 22:57

Removing blocker to allow m-nash to guide the review.

@mokarchi
Copy link
Author

@m-nash, Ready for your review. if there's anything else, please let me know.

Copy link
Collaborator

@m-nash m-nash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes LGTM, thanks again @mokarchi .

@joseharriaga can you also take a look to see if anything stands out where do we typically document things like this?

@m-nash
Copy link
Collaborator

m-nash commented Feb 12, 2026

@mokarchi looks like CI fails because you forgot to run ./scripts/Export-Api.ps1. You will need to run that and add those changed api files to the PR.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds first-class configuration binding and dependency injection registration for the OpenAI .NET clients using the System.ClientModel ClientSettings pattern, enabling per-client configuration and host-builder-based registrations.

Changes:

  • Introduces *ClientSettings types per specialized client, implementing configuration binding via ClientSettings.BindCore.
  • Adds new ClientSettings-based constructors across the specialized clients.
  • Adds IHostApplicationBuilder extension methods to register clients (including keyed registrations) via AddClient<TClient,TSettings> / AddKeyedClient<TClient,TSettings>.

Reviewed changes

Copilot reviewed 38 out of 38 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
src/Custom/DependencyInjection/OpenAIHostBuilderExtensions.cs Adds IHostApplicationBuilder extension methods for registering OpenAI clients (including keyed variants).
src/Custom/OpenAIClientOptions.cs Adds configuration-section-based binding constructor used by settings classes.
src/Custom/Chat/ChatClientSettings.cs Adds settings type to bind Model and nested Options for ChatClient.
src/Custom/Chat/ChatClient.cs Adds settings-based constructor for ChatClient.
src/Custom/Embeddings/EmbeddingClientSettings.cs Adds settings type to bind Model and nested Options for EmbeddingClient.
src/Custom/Embeddings/EmbeddingClient.cs Adds settings-based constructor for EmbeddingClient.
src/Custom/Audio/AudioClientSettings.cs Adds settings type to bind Model and nested Options for AudioClient.
src/Custom/Audio/AudioClient.cs Adds settings-based constructor for AudioClient.
src/Custom/Images/ImageClientSettings.cs Adds settings type to bind Model and nested Options for ImageClient.
src/Custom/Images/ImageClient.cs Adds settings-based constructor for ImageClient.
src/Custom/Moderations/ModerationClientSettings.cs Adds settings type to bind Model and nested Options for ModerationClient.
src/Custom/Moderations/ModerationClient.cs Adds settings-based constructor for ModerationClient.
src/Custom/Responses/ResponsesClientSettings.cs Adds settings type to bind Model and nested Options for ResponsesClient.
src/Custom/Responses/ResponsesClient.cs Adds settings-based constructor for ResponsesClient and a small whitespace-only change.
src/Custom/Assistants/AssistantClientSettings.cs Adds settings type to bind nested Options for AssistantClient.
src/Custom/Assistants/AssistantClient.cs Adds settings-based constructor for AssistantClient.
src/Custom/Batch/BatchClientSettings.cs Adds settings type to bind nested Options for BatchClient.
src/Custom/Batch/BatchClient.cs Adds settings-based constructor for BatchClient.
src/Custom/Containers/ContainerClientSettings.cs Adds settings type to bind nested Options for ContainerClient.
src/Custom/Containers/ContainerClient.cs Adds settings-based constructor for ContainerClient.
src/Custom/Conversations/ConversationClientSettings.cs Adds settings type to bind nested Options for ConversationClient.
src/Custom/Conversations/ConversationClient.cs Adds settings-based constructor for ConversationClient.
src/Custom/Evals/EvaluationClientSettings.cs Adds settings type to bind nested Options for EvaluationClient.
src/Custom/Evals/EvaluationClient.cs Adds settings-based constructor for EvaluationClient.
src/Custom/Files/OpenAIFileClientSettings.cs Adds settings type to bind nested Options for OpenAIFileClient.
src/Custom/Files/OpenAIFileClient.cs Adds settings-based constructor for OpenAIFileClient.
src/Custom/FineTuning/FineTuningClientSettings.cs Adds settings type to bind nested Options for FineTuningClient.
src/Custom/FineTuning/FineTuningClient.cs Adds settings-based constructor for FineTuningClient.
src/Custom/Graders/GraderClientSettings.cs Adds settings type to bind nested Options for GraderClient.
src/Custom/Graders/GraderClient.cs Adds settings-based constructor for GraderClient.
src/Custom/Models/OpenAIModelClientSettings.cs Adds settings type to bind nested Options for OpenAIModelClient.
src/Custom/Models/OpenAIModelClient.cs Adds settings-based constructor for OpenAIModelClient.
src/Custom/Realtime/RealtimeClientSettings.cs Adds settings type to bind nested Options for RealtimeClient.
src/Custom/Realtime/RealtimeClient.cs Adds settings-based constructor for RealtimeClient.
src/Custom/VectorStores/VectorStoreClientSettings.cs Adds settings type to bind nested Options for VectorStoreClient.
src/Custom/VectorStores/VectorStoreClient.cs Adds settings-based constructor for VectorStoreClient.
src/Custom/Videos/VideoClientSettings.cs Adds settings type to bind nested Options for VideoClient.
src/Custom/Videos/VideoClient.cs Adds settings-based constructor for VideoClient.

@mokarchi
Copy link
Author

@joseharriaga Thanks for the thorough review and all the detailed feedback! I've now applied all the requested changes.

@mokarchi
Copy link
Author

@m-nash @joseharriaga

  1. I ran ./scripts/Export-Api.ps1 It completed successfully and updated the API surface files. I committed and pushed them However, CI is still failing.
  2. With all previous feedback applied, I believe the PR is now complete and ready. If there are no more comments or adjustments needed from your side, please feel free to merge whenever convenient or let me know if anything else remains.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants