Skip to content

Instantly share code, notes, and snippets.

@JimBobSquarePants
Created November 10, 2020 21:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JimBobSquarePants/d5ea04fb5f2eed9950b228f51a588799 to your computer and use it in GitHub Desktop.
Save JimBobSquarePants/d5ea04fb5f2eed9950b228f51a588799 to your computer and use it in GitHub Desktop.
Allows the controlled running of scoped services with automatic cleanup.
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
namespace ThingsWhatImNotProudOf
{
/// <summary>
/// Allows the manufacture and running of items within a smaller lifetime scope than the parent.
/// To be used sparingly when unable to inject a service within the required scope.
/// </summary>
public sealed class ScopedServiceRunner
{
private readonly IServiceScopeFactory serviceScopeFactory;
/// <summary>
/// Initializes a new instance of the <see cref="ScopedServiceRunner"/> class.
/// </summary>
/// <param name="serviceScopeFactory">The scope factory.</param>
public ScopedServiceRunner(IServiceScopeFactory serviceScopeFactory)
=> this.serviceScopeFactory = serviceScopeFactory;
/// <summary>
/// Runs the given <see cref="Action{T}"/> in the current scope.
/// </summary>
/// <typeparam name="T">The type of object to invoke and run against.</typeparam>
/// <param name="command">The command to run.</param>
public void RunScoped<T>(Action<T> command)
{
using (IServiceScope scope = this.serviceScopeFactory.CreateScope())
{
// Scope disposes of all disposables.
command(scope.ServiceProvider.GetRequiredService<T>());
}
}
/// <summary>
/// Runs the given <see cref="Func{T, TResult}"/> in the current scope.
/// </summary>
/// <typeparam name="T">The type of object to invoke and run against.</typeparam>
/// <typeparam name="TResult">The type of result.</typeparam>
/// <param name="command">The command to run.</param>
/// <returns>The <typeparamref name="TResult"/>.</returns>
public TResult RunScoped<T, TResult>(Func<T, TResult> command)
{
using (IServiceScope scope = this.serviceScopeFactory.CreateScope())
{
// Scope disposes of all disposables.
return command(scope.ServiceProvider.GetRequiredService<T>());
}
}
/// <summary>
/// Runs the given <see cref="Func{T, TResult}"/> in the current scope.
/// </summary>
/// <typeparam name="T">The type of object to invoke and run against.</typeparam>
/// <typeparam name="TResult">The type of result.</typeparam>
/// <param name="command">The command to run.</param>
/// <returns>The <typeparamref name="TResult"/>.</returns>
public async Task<TResult> RunScopedAsync<T, TResult>(Func<T, Task<TResult>> command)
{
using (IServiceScope scope = this.serviceScopeFactory.CreateScope())
{
// Scope disposes of all disposables.
return await command(scope.ServiceProvider.GetRequiredService<T>());
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment