Browse Source

Changed IServiceProvider in CommandService.ExecuteAsync to a scoped provider. Added a command context accessor, and setting the value before beginning the execute. This will allow injected services in modules to access the current command context. This mirrors the behavior of Asp.Net Core's HttpContextAccessor.

pull/1147/head
Kevin Gysberg 7 years ago
parent
commit
33ac43a4b8
3 changed files with 43 additions and 0 deletions
  1. +20
    -0
      src/Discord.Net.Commands/CommandService.cs
  2. +16
    -0
      src/Discord.Net.Core/Commands/CommandContextAccessor.cs
  3. +7
    -0
      src/Discord.Net.Core/Commands/ICommandContextAccessor.cs

+ 20
- 0
src/Discord.Net.Commands/CommandService.cs View File

@@ -1,3 +1,6 @@
using Discord.Commands.Builders;
using Discord.Logging;
using Microsoft.Extensions.DependencyInjection;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@@ -350,8 +353,25 @@ namespace Discord.Commands
=> ExecuteAsync(context, context.Message.Content.Substring(argPos), services, multiMatchHandling); => ExecuteAsync(context, context.Message.Content.Substring(argPos), services, multiMatchHandling);
public async Task<IResult> ExecuteAsync(ICommandContext context, string input, IServiceProvider services, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) public async Task<IResult> ExecuteAsync(ICommandContext context, string input, IServiceProvider services, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{ {
// Create service scope and command context so dependent services can consume the command context, with a scoped lifespan
services = services ?? EmptyServiceProvider.Instance; services = services ?? EmptyServiceProvider.Instance;
using (var serviceScope = services.CreateScope())
{
var scopedServices = serviceScope.ServiceProvider;


// If the context accessor is registered in the IoC container, set it
var contextAccessor = scopedServices.GetService<ICommandContextAccessor>();
if (contextAccessor != null)
{
contextAccessor.CommandContext = context;
}
return await ExecuteAsyncInternal(context, input, scopedServices, multiMatchHandling);
}
}

internal async Task<IResult> ExecuteAsyncInternal(ICommandContext context, string input,
IServiceProvider services, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{
var searchResult = Search(input); var searchResult = Search(input);
if (!searchResult.IsSuccess) if (!searchResult.IsSuccess)
return searchResult; return searchResult;


+ 16
- 0
src/Discord.Net.Core/Commands/CommandContextAccessor.cs View File

@@ -0,0 +1,16 @@
using System.Threading;

namespace Discord.Commands
{
public class CommandContextAccessor : ICommandContextAccessor
{
private static AsyncLocal<ICommandContext> _commandContextCurrent = new AsyncLocal<ICommandContext>();

public ICommandContext CommandContext
{
get => _commandContextCurrent.Value;
set => _commandContextCurrent.Value = value;
}

}
}

+ 7
- 0
src/Discord.Net.Core/Commands/ICommandContextAccessor.cs View File

@@ -0,0 +1,7 @@
namespace Discord.Commands
{
public interface ICommandContextAccessor
{
ICommandContext CommandContext { get; set; }
}
}

Loading…
Cancel
Save