Skip to content

Commit

Permalink
feat: required outer services for agent accessor chain (#40)
Browse files Browse the repository at this point in the history
* feat: required outer services for agent accessor chain

this feature allows access to required services from the service provider that constructed the agent accessor chain

* refactor: appease codacy gods

also move the method which builds a service provider to a private static method, keep ctor tidy
  • Loading branch information
the-avid-engineer authored Jun 24, 2022
1 parent f4f55b8 commit 5d48792
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
39 changes: 35 additions & 4 deletions src/EntityDb.Common/Agents/AgentAccessorChain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,52 @@ public class AgentAccessorChain : IAgentAccessor
private readonly IAgentAccessor[] _agentAccessors;

/// <ignore/>
public AgentAccessorChain(ILogger<AgentAccessorChain> logger, IOptions<AgentAccessorChainOptions> options) : this(logger, options.Value)
public AgentAccessorChain
(
ILogger<AgentAccessorChain> logger,
IOptions<AgentAccessorChainOptions> options,
IServiceProvider outerServiceProvider
) : this(logger, options.Value, outerServiceProvider)
{
}

internal AgentAccessorChain(ILogger<AgentAccessorChain> logger, AgentAccessorChainOptions options)
internal AgentAccessorChain
(
ILogger<AgentAccessorChain> logger,
AgentAccessorChainOptions options,
IServiceProvider outerServiceProvider
)
{
var serviceProvider = options.ServiceCollection
.BuildServiceProvider();
var serviceProvider = GetServiceProvider(outerServiceProvider, options);

_logger = logger;
_agentAccessors = serviceProvider
.GetServices<IAgentAccessor>()
.ToArray();
}

private static IServiceProvider GetServiceProvider(IServiceProvider outerServiceProvider, AgentAccessorChainOptions options)
{
IServiceCollection serviceCollectionCopy = new ServiceCollection();

foreach (var (outerServiceType, innerServiceLifetime) in options.RequiredOuterServices)
{
serviceCollectionCopy.Add(new ServiceDescriptor
(
outerServiceType,
_ => outerServiceProvider.GetRequiredService(outerServiceType),
innerServiceLifetime
));
}

foreach (var serviceDescriptor in options.ServiceCollection)
{
serviceCollectionCopy.Add(serviceDescriptor);
}

return serviceCollectionCopy.BuildServiceProvider();
}

/// <inheritdoc />
public IAgent GetAgent()
{
Expand Down
16 changes: 15 additions & 1 deletion src/EntityDb.Common/Agents/AgentAccessorChainOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using EntityDb.Abstractions.Agents;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;

namespace EntityDb.Common.Agents;

Expand All @@ -9,7 +11,19 @@ namespace EntityDb.Common.Agents;
public sealed class AgentAccessorChainOptions
{
/// <summary>
/// A service collection used to resolve multiple instances of <see cref="IAgentAccessor"/>.
/// An inner service collection used to configure and resolve multiple instances of <see cref="IAgentAccessor"/>.
/// </summary>
public IServiceCollection ServiceCollection { get; } = new ServiceCollection();

/// <summary>
/// If any of the instances of <see cref="IAgentAccessor"/> which are added to <see cref="ServiceCollection"/>
/// have required dependencies that live in the outer service provider (the one constructing <see cref="AgentAccessorChainOptions"/>),
/// then you can specify them here.
/// </summary>
/// <remarks>
/// Note that the <see cref="ServiceLifetime.Scoped">ServiceLifetime.Scoped</see> is not supported,
/// and if the outer service is itself scoped, the agent accessor will not be able to receive it
/// because it is, itself, registered as a singleton service.
/// </remarks>
public Dictionary<Type, ServiceLifetime> RequiredOuterServices { get; } = new();
}

0 comments on commit 5d48792

Please sign in to comment.