Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion .github/workflows/ci-linux.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
tfm: [ 'net8.0', 'net9.0' ]
tfm: [ 'net8.0', 'net9.0', 'net10.0' ]

steps:
- uses: actions/checkout@v2
Expand All @@ -18,6 +18,7 @@ jobs:
dotnet-version: |
8.0.x
9.0.x
10.0.x
- name: Install dependencies
run: dotnet restore
- name: Build
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
dotnet-version: |
8.0.x
9.0.x
10.0.x
- name: Install dependencies
run: dotnet restore
- name: Build
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
dotnet-version: |
8.0.x
9.0.x
10.0.x
- name: Install dependencies
run: dotnet restore
- name: Build
Expand Down
8 changes: 6 additions & 2 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project>

<PropertyGroup>
<Version>1.0.0-alpha.23</Version>
<PackageVersion>1.0.0-alpha.23</PackageVersion>
<Version>1.0.0-alpha.24</Version>
<PackageVersion>1.0.0-alpha.24</PackageVersion>
<Authors>Zapto</Authors>
<RepositoryUrl>https://github.com/zapto-dev/Mediator</RepositoryUrl>
<Copyright>Copyright © 2025 Zapto</Copyright>
Expand All @@ -19,4 +19,8 @@
<ExtensionVersion>9.0.0</ExtensionVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net10.0'">
<ExtensionVersion>10.0.0</ExtensionVersion>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -37,8 +36,27 @@ internal interface INotificationCache

internal sealed class GenericNotificationCache<TNotification> : INotificationCache
{
public GenericNotificationCache(IEnumerable<GenericNotificationRegistration> registrations)
{
var notificationType = typeof(TNotification);
if (notificationType.IsGenericType)
{
var genericType = notificationType.GetGenericTypeDefinition();
MatchingRegistrations = GenericTypeHelper.CacheMatchingRegistrations(
registrations,
r => r.NotificationType,
genericType);
}
else
{
MatchingRegistrations = new List<GenericNotificationRegistration>();
}
}

public List<Type>? HandlerTypes { get; set; }

public List<GenericNotificationRegistration> MatchingRegistrations { get; }

public List<IHandlerRegistration> Registrations { get; } = new();

public SemaphoreSlim Lock { get; } = new(1, 1);
Expand All @@ -48,12 +66,10 @@ internal sealed class GenericNotificationHandler<TNotification>
where TNotification : INotification
{
private readonly GenericNotificationCache<TNotification> _cache;
private readonly IEnumerable<GenericNotificationRegistration> _enumerable;
private readonly IServiceProvider _serviceProvider;

public GenericNotificationHandler(IEnumerable<GenericNotificationRegistration> enumerable, IServiceProvider serviceProvider, GenericNotificationCache<TNotification> cache)
public GenericNotificationHandler(IServiceProvider serviceProvider, GenericNotificationCache<TNotification> cache)
{
_enumerable = enumerable;
_serviceProvider = serviceProvider;
_cache = cache;
}
Expand Down Expand Up @@ -95,17 +111,24 @@ public async ValueTask<bool> Handle(IServiceProvider provider, TNotification not
var genericType = notificationType.GetGenericTypeDefinition();
var handlerTypes = new List<Type>();

foreach (var registration in _enumerable)

foreach (var registration in _cache.MatchingRegistrations)
{
if (registration.NotificationType != genericType)
Type type;
if (registration.HandlerType.IsGenericType)
{
if (!GenericTypeHelper.CanMakeGenericType(registration.HandlerType, arguments))
{
continue;
}

type = registration.HandlerType.MakeGenericType(arguments);
}
else
{
continue;
type = registration.HandlerType;
}

var type = registration.HandlerType.IsGenericType
? registration.HandlerType.MakeGenericType(arguments)
: registration.HandlerType;

var handler = _serviceProvider.GetRequiredService(type);

await ((INotificationHandler<TNotification>)handler!).Handle(provider, notification, ct);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
Expand Down Expand Up @@ -27,29 +26,64 @@ public GenericRequestRegistration(Type requestType, Type? responseType, Type han

internal sealed class GenericRequestCache<TRequest, TResponse>
{
public GenericRequestCache(IEnumerable<GenericRequestRegistration> registrations)
{
var requestType = typeof(TRequest);
if (requestType.IsGenericType)
{
var genericType = requestType.GetGenericTypeDefinition();
MatchingRegistrations = GenericTypeHelper.CacheMatchingRegistrations(
registrations,
r => r.RequestType,
genericType);
}
else
{
MatchingRegistrations = new List<GenericRequestRegistration>();
}
}

public Type? RequestHandlerType { get; set; }

public List<GenericRequestRegistration> MatchingRegistrations { get; }
}

internal sealed class GenericRequestCache<TRequest>
{
public GenericRequestCache(IEnumerable<GenericRequestRegistration> registrations)
{
var requestType = typeof(TRequest);
if (requestType.IsGenericType)
{
var genericType = requestType.GetGenericTypeDefinition();
MatchingRegistrations = GenericTypeHelper.CacheMatchingRegistrations(
registrations,
r => r.RequestType,
genericType);
}
else
{
MatchingRegistrations = new List<GenericRequestRegistration>();
}
}

public Type? RequestHandlerType { get; set; }

public List<GenericRequestRegistration> MatchingRegistrations { get; }
}

internal sealed class GenericRequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly GenericRequestCache<TRequest, TResponse> _cache;
private readonly IEnumerable<GenericRequestRegistration> _enumerable;
private readonly IServiceProvider _serviceProvider;
private readonly IDefaultRequestHandler? _defaultHandler;

public GenericRequestHandler(
IEnumerable<GenericRequestRegistration> enumerable,
IServiceProvider serviceProvider,
GenericRequestCache<TRequest, TResponse> cache,
IDefaultRequestHandler? defaultHandler = null)
{
_enumerable = enumerable;
_serviceProvider = serviceProvider;
_cache = cache;
_defaultHandler = defaultHandler;
Expand Down Expand Up @@ -86,17 +120,29 @@ public async ValueTask<TResponse> Handle(IServiceProvider provider, TRequest req
responseType = responseType.GetGenericTypeDefinition();
}

foreach (var registration in _enumerable)

foreach (var registration in _cache.MatchingRegistrations)
{
if (registration.RequestType != requestType ||
registration.ResponseType is not null && registration.ResponseType != responseType)
if (registration.ResponseType is not null && registration.ResponseType != responseType)
{
continue;
}

var type = registration.HandlerType.IsGenericType
? registration.HandlerType.MakeGenericType(arguments)
: registration.HandlerType;
Type type;
if (registration.HandlerType.IsGenericType)
{
// Check if the generic arguments satisfy the handler's constraints
if (!GenericTypeHelper.CanMakeGenericType(registration.HandlerType, arguments))
{
continue;
}

type = registration.HandlerType.MakeGenericType(arguments);
}
else
{
type = registration.HandlerType;
}

var handler = (IRequestHandler<TRequest, TResponse>) _serviceProvider.GetRequiredService(type);

Expand Down Expand Up @@ -125,17 +171,14 @@ internal sealed class GenericRequestHandler<TRequest> : IRequestHandler<TRequest
where TRequest : IRequest
{
private readonly GenericRequestCache<TRequest> _cache;
private readonly IEnumerable<GenericRequestRegistration> _enumerable;
private readonly IServiceProvider _serviceProvider;
private readonly IDefaultRequestHandler? _defaultHandler;

public GenericRequestHandler(
IEnumerable<GenericRequestRegistration> enumerable,
IServiceProvider serviceProvider,
GenericRequestCache<TRequest> cache,
IDefaultRequestHandler? defaultHandler = null)
{
_enumerable = enumerable;
_serviceProvider = serviceProvider;
_cache = cache;
_defaultHandler = defaultHandler;
Expand Down Expand Up @@ -168,15 +211,30 @@ public async ValueTask Handle(IServiceProvider provider, TRequest request, Cance

requestType = requestType.GetGenericTypeDefinition();

foreach (var registration in _enumerable)

foreach (var registration in _cache.MatchingRegistrations)
{
if (registration.RequestType != requestType ||
registration.ResponseType != typeof(Unit))
if (registration.ResponseType != typeof(Unit))
{
continue;
}

var type = registration.HandlerType.MakeGenericType(arguments);
Type type;
if (registration.HandlerType.IsGenericType)
{
// Check if the generic arguments satisfy the handler's constraints
if (!GenericTypeHelper.CanMakeGenericType(registration.HandlerType, arguments))
{
continue;
}

type = registration.HandlerType.MakeGenericType(arguments);
}
else
{
type = registration.HandlerType;
}

var handler = (IRequestHandler<TRequest>) _serviceProvider.GetRequiredService(type);

_cache.RequestHandlerType = type;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -26,24 +24,40 @@ public GenericStreamRequestRegistration(Type requestType, Type? responseType, Ty

internal sealed class GenericStreamRequestCache<TRequest, TResponse>
{
public GenericStreamRequestCache(IEnumerable<GenericStreamRequestRegistration> registrations)
{
var requestType = typeof(TRequest);
if (requestType.IsGenericType)
{
var genericType = requestType.GetGenericTypeDefinition();
MatchingRegistrations = GenericTypeHelper.CacheMatchingRegistrations(
registrations,
r => r.RequestType,
genericType);
}
else
{
MatchingRegistrations = new List<GenericStreamRequestRegistration>();
}
}

public Type? RequestHandlerType { get; set; }

public List<GenericStreamRequestRegistration> MatchingRegistrations { get; }
}

internal sealed class GenericStreamRequestHandler<TRequest, TResponse> : IStreamRequestHandler<TRequest, TResponse>
where TRequest : IStreamRequest<TResponse>
{
private readonly GenericStreamRequestCache<TRequest, TResponse> _cache;
private readonly IEnumerable<GenericStreamRequestRegistration> _enumerable;
private readonly IServiceProvider _serviceProvider;
private readonly IDefaultStreamRequestHandler? _defaultHandler;

public GenericStreamRequestHandler(
IEnumerable<GenericStreamRequestRegistration> enumerable,
IServiceProvider serviceProvider,
GenericStreamRequestCache<TRequest, TResponse> cache,
IDefaultStreamRequestHandler? defaultHandler = null)
{
_enumerable = enumerable;
_serviceProvider = serviceProvider;
_cache = cache;
_defaultHandler = defaultHandler;
Expand Down Expand Up @@ -80,17 +94,29 @@ public IAsyncEnumerable<TResponse> Handle(IServiceProvider provider, TRequest re
responseType = responseType.GetGenericTypeDefinition();
}

foreach (var registration in _enumerable)

foreach (var registration in _cache.MatchingRegistrations)
{
if (registration.RequestType != requestType ||
registration.ResponseType is not null && registration.ResponseType != responseType)
if (registration.ResponseType is not null && registration.ResponseType != responseType)
{
continue;
}

var type = registration.HandlerType.IsGenericType
? registration.HandlerType.MakeGenericType(arguments)
: registration.HandlerType;
Type type;
if (registration.HandlerType.IsGenericType)
{
// Check if the generic arguments satisfy the handler's constraints
if (!GenericTypeHelper.CanMakeGenericType(registration.HandlerType, arguments))
{
continue;
}

type = registration.HandlerType.MakeGenericType(arguments);
}
else
{
type = registration.HandlerType;
}

var handler = (IStreamRequestHandler<TRequest, TResponse>) _serviceProvider.GetRequiredService(type);

Expand Down
Loading
Loading