Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ namespace NServiceBus;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;

class KeyedServiceCollectionAdapter : IServiceCollection
Expand All @@ -19,54 +18,33 @@ public KeyedServiceCollectionAdapter(IServiceCollection inner, object serviceKey

Inner = inner;
ServiceKey = new KeyedServiceKey(serviceKey);
gate = sharedStates.GetValue(inner, _ => new SharedState()).Gate;
}

public KeyedServiceKey ServiceKey { get; }

public IServiceCollection Inner
{
get
{
using var _ = gate.EnterScope();
return field;
}
}
public IServiceCollection Inner { get; }

public ServiceDescriptor this[int index]
{
get
{
using var _ = gate.EnterScope();
return descriptors[index];
}
get => descriptors[index];
set => throw new NotSupportedException("Replacing service descriptors is not supported for multi endpoint services.");
}

public int Count
{
get
{
using var _ = gate.EnterScope();
return descriptors.Count;
}
}
public int Count => descriptors.Count;

public bool IsReadOnly => false;

public void Add(ServiceDescriptor item)
{
ArgumentNullException.ThrowIfNull(item);

using Lock.Scope _ = gate.EnterScope();
var keyedDescriptor = EnsureKeyedDescriptor(item);
descriptors.Add(keyedDescriptor);
Inner.Add(keyedDescriptor);
}

public void Clear()
{
using Lock.Scope scope = gate.EnterScope();
foreach (var descriptor in descriptors)
{
_ = Inner.Remove(descriptor);
Expand All @@ -80,27 +58,17 @@ public bool Contains(ServiceDescriptor item)
{
ArgumentNullException.ThrowIfNull(item);

using var _ = gate.EnterScope();
return descriptors.Contains(item);
}

public void CopyTo(ServiceDescriptor[] array, int arrayIndex)
{
using var _ = gate.EnterScope();
descriptors.CopyTo(array, arrayIndex);
}
public void CopyTo(ServiceDescriptor[] array, int arrayIndex) => descriptors.CopyTo(array, arrayIndex);

public IEnumerator<ServiceDescriptor> GetEnumerator()
{
using var _ = gate.EnterScope();
return ((IEnumerable<ServiceDescriptor>)[.. descriptors]).GetEnumerator();
}
public IEnumerator<ServiceDescriptor> GetEnumerator() => ((IEnumerable<ServiceDescriptor>)[.. descriptors]).GetEnumerator();

public int IndexOf(ServiceDescriptor item)
{
ArgumentNullException.ThrowIfNull(item);

using var _ = gate.EnterScope();
return descriptors.IndexOf(item);
}

Expand All @@ -110,7 +78,6 @@ public bool Remove(ServiceDescriptor item)
{
ArgumentNullException.ThrowIfNull(item);

using Lock.Scope scope = gate.EnterScope();
if (!descriptors.Remove(item))
{
return false;
Expand All @@ -123,7 +90,6 @@ public bool Remove(ServiceDescriptor item)

public void RemoveAt(int index)
{
using Lock.Scope scope = gate.EnterScope();
var descriptor = descriptors[index];
descriptors.RemoveAt(index);
_ = Inner.Remove(descriptor);
Expand All @@ -136,7 +102,6 @@ public bool ContainsService(Type serviceType)
{
ArgumentNullException.ThrowIfNull(serviceType);

using var _ = gate.EnterScope();
if (serviceTypeCounts.ContainsKey(serviceType))
{
return true;
Expand Down Expand Up @@ -252,14 +217,4 @@ static class UnsafeAccessor
readonly List<ServiceDescriptor> descriptors = [];
readonly Dictionary<Type, int> serviceTypeCounts = [];
readonly ConcurrentDictionary<Type, ObjectFactory> factories = new();
readonly Lock gate;

// We need to keep track of the locks per service collection to avoid potential deadlocks between different adapters sharing the same underlying collection.
// We use a ConditionalWeakTable here to avoid leaking memory in case service collections are not properly disposed.
static readonly ConditionalWeakTable<IServiceCollection, SharedState> sharedStates = [];

sealed class SharedState
{
public Lock Gate { get; } = new();
}
}
Loading