Skip to content

.Net MEVD: Dependency Injection for SqlServer connector #11594

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

Closed

Conversation

adamsitnik
Copy link
Member

@roji @westey-m Once this PR gets approved, I would like to apply similar pattern to other connectors. Namely:

  • ServiceLifetime.Singleton is the default, but users can provide other values if they want to (idea taken from .Net: First round of MEVD DI changes #10960, this is what I've been doing in projects like Aspire or HealthChecks)
  • using AddKeyed prefix for the methods that register a keyed instance (also taken from .Net: First round of MEVD DI changes #10960)
  • instead of accepting raw connection strings (and similar settings), we should be accepting a Func<IServiceProvider, string> so the users can read the value from the settings.

Sample:

services.AddSqlServerVectorStore(sp => sp.GetRequiredService<IConfiguration>().GetConnectionString("SqlServer")!);

services.AddSqlServerVectorStore(_ => "Server=localhost;Database=master;Integrated Security=True;");

fixes #10948

@adamsitnik adamsitnik requested review from roji and westey-m April 16, 2025 17:20
@adamsitnik adamsitnik requested a review from a team as a code owner April 16, 2025 17:20
@markwallace-microsoft markwallace-microsoft added .NET Issue or Pull requests regarding .NET code kernel Issues or pull requests impacting the core kernel memory labels Apr 16, 2025
/// <param name="lifetime">The service lifetime for the store. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The service collection.</returns>
public static IServiceCollection AddSqlServerVectorStore(this IServiceCollection services,
Func<IServiceProvider, string> connectionStringProvider,
Copy link
Member

Choose a reason for hiding this comment

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

Not sure, but... I think the basic expectation any user would have is to be able to pass the connection string directly (without a function). I get the logic of accepting a Func (to construct a connection string based on config that's in DI, e.g. tenant ID as database name), but it's definitely a bit jarring/unexpected for the minimal demo to look like this: AddSqlServerVectorStore(_ => "blablabla").

FWIW IIRC EF only accepts a string directly; AddNpgsqlDataSource is the same (though there's an issue for adding an overload that accepts an IServiceProvider Func. I'm not sure what they did in Aspire - might be worth checking.

The easy answer here is obviously to just have two overloads - one with a string, one with a Func. The only concern here is that we risk going into DI overload explosion: we have:

  1. String vs. Func. For PG there's also NpgsqlDataSource (and this is also planned for SQL Server, Sqlite...).
  2. Regular vs. Keyed
  3. IVectorStore vs. IVectorStoreRecordCollection
  4. We may end up needing POCO vs. dynamic mapping - the former will be not safe for trimming. After Build we'll also introduce another POCO one which accepts source-generated stuff, for trimming-safe POCO mapping (so 3 overall)

So I'm not sure where this will go - let's maybe discuss this in parking lot soon.

Copy link
Contributor

Choose a reason for hiding this comment

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

@roji, is you concern around having many overloads born from complexity of use, or from maintaining so many overloads?

Copy link
Member Author

Choose a reason for hiding this comment

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

@roji @westey-m I've moved the conversation to the issue: #10549 (comment) PTAL

{
protected abstract void PopulateConfiguration(ConfigurationManager configuration, object? serviceKey = null);

protected abstract void RegisterVectorStore(IServiceCollection services, ServiceLifetime lifetime, object? serviceKey = null);
Copy link
Member

Choose a reason for hiding this comment

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

Since there are several registration methods, maybe better to allow connectors to expose a list of delegates on their fixtures and perform tests over all of them.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.VectorData;

namespace Microsoft.SemanticKernel.Connectors.SqlServer;
Copy link
Member

Choose a reason for hiding this comment

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

I think it's common practice to put DI registration methods in a very general namespace so that they light up with an extra using, e.g. Microsoft.Extensions.VectorData (though I seem to remember that this was slightly controversial).

Copy link
Member Author

Choose a reason for hiding this comment

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

Other connectors went one step further and have defined their extension methods in Microsoft.SemanticKernel:

@westey-m @roji is that desired?

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe another approach is to have them in the namespace of the thing that is being registered on, in this case that of ServiceCollection, which does make sense to me too.

Copy link
Member Author

Choose a reason for hiding this comment

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

- register concrete, provider-specific types, not just the abstractions
- have overloads that accept raw connection string (and just options, not an option provider)
@westey-m westey-m deleted the branch microsoft:feature-vector-data-preb2 April 29, 2025 15:43
@westey-m westey-m closed this Apr 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kernel Issues or pull requests impacting the core kernel memory .NET Issue or Pull requests regarding .NET code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants