Skip to content

Conversation

@georg-jung
Copy link

This adds support for scoped services from the service provider using IServiceScope without taking a dependency on Microsoft.Extensions.DependencyInjection.Abstractions.

Motivation

I want to implement an IUserAuthenticator that consumes a UserManager<AppUser> userManager from ASP.NET Core Identity. This is typically registered as a scoped service. ISessionContext.ServiceProvider does however return the root SP. I think SMTP is a rather good fit for the scoped scenario. As a scope in Http corresponds to one request, a scope in Smtp can correspond to one Smtp session (one could argue it could also correspond to one SmtpCommand but I think the connection makes more sense for SMTP, given it is stateful).

Usage

If this is merged, one can easily add a class like this in his codebase that does depend on Microsoft.Extensions.DependencyInjection.Abstractions:

using SmtpServer;

namespace SomeApp;

internal class ScopedSessionServiceProviderFactory : ISessionServiceProviderFactory
{
    public IServiceProvider CreateServiceProvider(IServiceProvider rootServiceProvider)
    {
        return new DelegatingScopeProvider(rootServiceProvider.CreateAsyncScope());
    }

    // inspired by https://github.com/dotnet/runtime/blob/08298b48fd98df648d90c73e058522e4ac2eb008/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
    private class DelegatingScopeProvider(IServiceScope delegateTo) : IServiceProvider, IAsyncDisposable, IDisposable
    {
        public void Dispose()
        {
            delegateTo.Dispose();
        }

        public ValueTask DisposeAsync()
        {
            if (delegateTo is IAsyncDisposable ad)
            {
                return ad.DisposeAsync();
            }

            delegateTo.Dispose();
            return ValueTask.CompletedTask;
        }

        object? IServiceProvider.GetService(Type serviceType) => delegateTo.ServiceProvider.GetService(serviceType);
    }
}

And register this class in the app's DI container like this:

builder.Services.AddSingleton<ISessionServiceProviderFactory, ScopedSessionServiceProviderFactory>();

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.

1 participant