Skip to content

Commit

Permalink
General Updates:
Browse files Browse the repository at this point in the history
- [FIX] key exists exception when multiple handlers registered for an operation (resolve the last registered handler type)
- update deps
  • Loading branch information
Cryptoc1 committed Sep 30, 2024
1 parent e23de36 commit fc04e73
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 97 deletions.
4 changes: 2 additions & 2 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
<ItemGroup Condition=" '$(IsTestProject)' == 'true' ">
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.analyzers" Version="1.16.0" />
<PackageReference Include="xunit.runner.console" Version="2.9.1" />
<PackageReference Include="xunit.runner.console" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />

<Using Include="Xunit" />
Expand Down
27 changes: 27 additions & 0 deletions src/OperationInvoker/HandlerDescriptorResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace ESCd.Extensions.OperationInvoker;

internal sealed class HandlerDescriptorResolver( IEnumerable<OperationHandlerDescriptor> descriptors )
{
private readonly Dictionary<Type, OperationHandlerDescriptor> descriptorsByOperationType = ToDictionary( descriptors );

public OperationHandlerDescriptor? Resolve( Type operationType )
{
if( descriptorsByOperationType.TryGetValue( operationType, out var descriptor ) )
{
return descriptor;
}

return default;
}

private static Dictionary<Type, OperationHandlerDescriptor> ToDictionary( IEnumerable<OperationHandlerDescriptor> descriptors )
{
var descriptorsByOperationType = new Dictionary<Type, OperationHandlerDescriptor>();
foreach( var descriptor in descriptors )
{
descriptorsByOperationType[ descriptor.OperationType ] = descriptor;
}

return descriptorsByOperationType;
}
}
21 changes: 3 additions & 18 deletions src/OperationInvoker/OperationInvoker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace ESCd.Extensions.OperationInvoker;

internal sealed class OperationInvoker( HandlerDescriptorFinder descriptorFinder, IServiceProvider serviceProvider ) : IOperationInvoker
internal sealed class OperationInvoker( HandlerDescriptorResolver descriptorResolver, IServiceProvider serviceProvider ) : IOperationInvoker
{
public async Task Invoke( IOperation operation, CancellationToken cancellation )
{
Expand Down Expand Up @@ -45,24 +45,9 @@ public async Task<TResult> Invoke<TResult>( IOperation<TResult> operation, Cance

private (OperationHandlerDescriptor Descriptor, object Handler) ResolveHandler( Type type )
{
var descriptor = descriptorFinder.Find( type ) ?? throw new ArgumentException( $"An IOperationHandler for {type} has not been registered to the service provider.", nameof( type ) );
var descriptor = descriptorResolver.Resolve( type ) ?? throw new ArgumentException( $"An IOperationHandler for {type} has not been registered to the service provider.", nameof( type ) );
return (
descriptor,
descriptor.Instance ?? ActivatorUtilities.CreateInstance( serviceProvider, descriptor.HandlerType ));
}
};

internal sealed class HandlerDescriptorFinder( IEnumerable<OperationHandlerDescriptor> descriptors )
{
private readonly Dictionary<Type, OperationHandlerDescriptor> descriptorsByOperationType = descriptors.ToDictionary( handler => handler.OperationType );

public OperationHandlerDescriptor? Find( Type operationType )
{
if( descriptorsByOperationType.TryGetValue( operationType, out var descriptor ) )
{
return descriptor;
}

return default;
}
}
};
2 changes: 1 addition & 1 deletion src/OperationInvoker/OperationServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static IServiceCollection AddOperationInvoker( this IServiceCollection se
{
ArgumentNullException.ThrowIfNull( services );

services.TryAddSingleton<HandlerDescriptorFinder>();
services.TryAddSingleton<HandlerDescriptorResolver>();
services.TryAddTransient<IOperationInvoker, OperationInvoker>();
return services;
}
Expand Down
76 changes: 38 additions & 38 deletions test/Http/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@
},
"xunit": {
"type": "Direct",
"requested": "[2.9.1, )",
"resolved": "2.9.1",
"contentHash": "db2l1I1Tde7OivowgxoxKgmqFl02KoOjFOQhV1FSVu+odTIntjhQhMwKIVvyWjBO6t7tS0PnFxblwSqeUuRZMQ==",
"requested": "[2.9.2, )",
"resolved": "2.9.2",
"contentHash": "7LhFS2N9Z6Xgg8aE5lY95cneYivRMfRI8v+4PATa4S64D5Z/Plkg0qa8dTRHSiGRgVZ/CL2gEfJDE5AUhOX+2Q==",
"dependencies": {
"xunit.analyzers": "1.16.0",
"xunit.assert": "2.9.1",
"xunit.core": "[2.9.1]"
"xunit.assert": "2.9.2",
"xunit.core": "[2.9.2]"
}
},
"xunit.analyzers": {
Expand All @@ -65,9 +65,9 @@
},
"xunit.runner.console": {
"type": "Direct",
"requested": "[2.9.1, )",
"resolved": "2.9.1",
"contentHash": "b9zEDvO2QN4cVOw0e7RzK4ZoXhJN7iSiaC5QaJJhvjnYeTYsTn1zX9PX1ncxGZao7ZXdg0T9qQDIH0xK4lpiNA=="
"requested": "[2.9.2, )",
"resolved": "2.9.2",
"contentHash": "bzxrKRk1rm2ro//ElUS8MEejvOjYIpXHbt3XrziYBrY9qgqeOb6ULELRshts3M7N6V+wtuRb78u9GJZjqASVdQ=="
},
"xunit.runner.visualstudio": {
"type": "Direct",
Expand Down Expand Up @@ -275,32 +275,32 @@
},
"xunit.assert": {
"type": "Transitive",
"resolved": "2.9.1",
"contentHash": "Pb7x7MPfFgwRt88sJGbct/h7cc0wyxFHPhA2X0P8mUdPyrOTLN7QgsxX8ZFkJKm+Yj8YMKYOCzXtRWOGlMYjZw=="
"resolved": "2.9.2",
"contentHash": "QkNBAQG4pa66cholm28AxijBjrmki98/vsEh4Sx5iplzotvPgpiotcxqJQMRC8d7RV7nIT8ozh97957hDnZwsQ=="
},
"xunit.core": {
"type": "Transitive",
"resolved": "2.9.1",
"contentHash": "39DvKrtALB6DknhJrhTIwKF5wwuWqohGT0tEJnOstT2NfoDbvVKFv/hlgM6hH2ghUsxOhP0gHmj7HOR4D21fow==",
"resolved": "2.9.2",
"contentHash": "O6RrNSdmZ0xgEn5kT927PNwog5vxTtKrWMihhhrT0Sg9jQ7iBDciYOwzBgP2krBEk5/GBXI18R1lKvmnxGcb4w==",
"dependencies": {
"xunit.extensibility.core": "[2.9.1]",
"xunit.extensibility.execution": "[2.9.1]"
"xunit.extensibility.core": "[2.9.2]",
"xunit.extensibility.execution": "[2.9.2]"
}
},
"xunit.extensibility.core": {
"type": "Transitive",
"resolved": "2.9.1",
"contentHash": "lAsb+57Lk2gA/LW/IzlGlq0vyx5AgLtadJyGBUaS353HJT++qKdMlYi74pWgai7RLTnkV4ayownPredKe8REZQ==",
"resolved": "2.9.2",
"contentHash": "Ol+KlBJz1x8BrdnhN2DeOuLrr1I/cTwtHCggL9BvYqFuVd/TUSzxNT5O0NxCIXth30bsKxgMfdqLTcORtM52yQ==",
"dependencies": {
"xunit.abstractions": "2.0.3"
}
},
"xunit.extensibility.execution": {
"type": "Transitive",
"resolved": "2.9.1",
"contentHash": "KJ2LE0lOaN2wxtwwfM9nii218nzmxwMAqpolQJ0ZoLtZQ3gfJ1XtbEywGOCGZf9zBe9pPBEILqQaUO04lnekvQ==",
"resolved": "2.9.2",
"contentHash": "rKMpq4GsIUIJibXuZoZ8lYp5EpROlnYaRpwu9Zr0sRZXE7JqJfEEbCsUriZqB+ByXCLFBJyjkTRULMdC+U566g==",
"dependencies": {
"xunit.extensibility.core": "[2.9.1]"
"xunit.extensibility.core": "[2.9.2]"
}
},
"escd.extensions.http": {
Expand Down Expand Up @@ -361,13 +361,13 @@
},
"xunit": {
"type": "Direct",
"requested": "[2.9.1, )",
"resolved": "2.9.1",
"contentHash": "db2l1I1Tde7OivowgxoxKgmqFl02KoOjFOQhV1FSVu+odTIntjhQhMwKIVvyWjBO6t7tS0PnFxblwSqeUuRZMQ==",
"requested": "[2.9.2, )",
"resolved": "2.9.2",
"contentHash": "7LhFS2N9Z6Xgg8aE5lY95cneYivRMfRI8v+4PATa4S64D5Z/Plkg0qa8dTRHSiGRgVZ/CL2gEfJDE5AUhOX+2Q==",
"dependencies": {
"xunit.analyzers": "1.16.0",
"xunit.assert": "2.9.1",
"xunit.core": "[2.9.1]"
"xunit.assert": "2.9.2",
"xunit.core": "[2.9.2]"
}
},
"xunit.analyzers": {
Expand All @@ -378,9 +378,9 @@
},
"xunit.runner.console": {
"type": "Direct",
"requested": "[2.9.1, )",
"resolved": "2.9.1",
"contentHash": "b9zEDvO2QN4cVOw0e7RzK4ZoXhJN7iSiaC5QaJJhvjnYeTYsTn1zX9PX1ncxGZao7ZXdg0T9qQDIH0xK4lpiNA=="
"requested": "[2.9.2, )",
"resolved": "2.9.2",
"contentHash": "bzxrKRk1rm2ro//ElUS8MEejvOjYIpXHbt3XrziYBrY9qgqeOb6ULELRshts3M7N6V+wtuRb78u9GJZjqASVdQ=="
},
"xunit.runner.visualstudio": {
"type": "Direct",
Expand Down Expand Up @@ -571,32 +571,32 @@
},
"xunit.assert": {
"type": "Transitive",
"resolved": "2.9.1",
"contentHash": "Pb7x7MPfFgwRt88sJGbct/h7cc0wyxFHPhA2X0P8mUdPyrOTLN7QgsxX8ZFkJKm+Yj8YMKYOCzXtRWOGlMYjZw=="
"resolved": "2.9.2",
"contentHash": "QkNBAQG4pa66cholm28AxijBjrmki98/vsEh4Sx5iplzotvPgpiotcxqJQMRC8d7RV7nIT8ozh97957hDnZwsQ=="
},
"xunit.core": {
"type": "Transitive",
"resolved": "2.9.1",
"contentHash": "39DvKrtALB6DknhJrhTIwKF5wwuWqohGT0tEJnOstT2NfoDbvVKFv/hlgM6hH2ghUsxOhP0gHmj7HOR4D21fow==",
"resolved": "2.9.2",
"contentHash": "O6RrNSdmZ0xgEn5kT927PNwog5vxTtKrWMihhhrT0Sg9jQ7iBDciYOwzBgP2krBEk5/GBXI18R1lKvmnxGcb4w==",
"dependencies": {
"xunit.extensibility.core": "[2.9.1]",
"xunit.extensibility.execution": "[2.9.1]"
"xunit.extensibility.core": "[2.9.2]",
"xunit.extensibility.execution": "[2.9.2]"
}
},
"xunit.extensibility.core": {
"type": "Transitive",
"resolved": "2.9.1",
"contentHash": "lAsb+57Lk2gA/LW/IzlGlq0vyx5AgLtadJyGBUaS353HJT++qKdMlYi74pWgai7RLTnkV4ayownPredKe8REZQ==",
"resolved": "2.9.2",
"contentHash": "Ol+KlBJz1x8BrdnhN2DeOuLrr1I/cTwtHCggL9BvYqFuVd/TUSzxNT5O0NxCIXth30bsKxgMfdqLTcORtM52yQ==",
"dependencies": {
"xunit.abstractions": "2.0.3"
}
},
"xunit.extensibility.execution": {
"type": "Transitive",
"resolved": "2.9.1",
"contentHash": "KJ2LE0lOaN2wxtwwfM9nii218nzmxwMAqpolQJ0ZoLtZQ3gfJ1XtbEywGOCGZf9zBe9pPBEILqQaUO04lnekvQ==",
"resolved": "2.9.2",
"contentHash": "rKMpq4GsIUIJibXuZoZ8lYp5EpROlnYaRpwu9Zr0sRZXE7JqJfEEbCsUriZqB+ByXCLFBJyjkTRULMdC+U566g==",
"dependencies": {
"xunit.extensibility.core": "[2.9.1]"
"xunit.extensibility.core": "[2.9.2]"
}
},
"escd.extensions.http": {
Expand Down
32 changes: 32 additions & 0 deletions test/OperationInvoker/HandlerDescriptorResolverTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using ESCd.Extensions.OperationInvoker.Abstractions;
using Microsoft.Extensions.DependencyInjection;

namespace ESCd.Extensions.OperationInvoker.Tests;

public sealed class HandlerDescriptorResolverTests
{
[Fact( DisplayName = "Resolve: returns last registered handler" )]
public void Resolve_Returns_LastRegisteredHandler( )
{
using var services = new ServiceCollection()
.AddOperationHandler<TestHandler>()
.AddOperationHandler<OtherTestHandler>()
.BuildServiceProvider();

var resolver = services.GetRequiredService<HandlerDescriptorResolver>();
var descriptor = resolver.Resolve( typeof( TestOperation ) );

Assert.Equal( typeof( OtherTestHandler ), descriptor?.HandlerType );
}

private sealed record TestOperation : IOperation;
private sealed class TestHandler : IOperationHandler<TestOperation>
{
public Task Invoke( TestOperation operation, CancellationToken cancellation ) => throw new NotImplementedException();
}

private sealed class OtherTestHandler : IOperationHandler<TestOperation>
{
public Task Invoke( TestOperation operation, CancellationToken cancellation ) => throw new NotImplementedException();
}
}
Loading

0 comments on commit fc04e73

Please sign in to comment.