Over the years, I have come across many projects in which:
Query/Command models (hereinafter objects implementing IRequest) were stored in the Domain layer
Handlers in the Application layer
Calling to IMediator.Send in the Presentation layer.
All the listed objects have an internal access modifier, and the .csproj files specify the InternalsVisibleTo tag up to the overlying layers.
At the moment, in my current company, migration from Jimmy Bogart'sMediatR to the current implementation is being discussed due to its advantages; however, the problem described above forces us, for the time being, to refrain from that.
Description of the problem
In cases where internal Handler, internal request, and internal response are used, Inconsistent accessibility occurs. The problem is that the generated Mediator.Send method is public, when it's input parameter and return value are internal.
Handler
namespace ServiceDesk.Appeals.Application.Handlers;
internal sealed class GetHelloCustomerQueryHandler : IRequestHandler<GetHelloCustomerQuery, GetHelloCustomerQueryResponse>
{
public ValueTask<GetHelloCustomerQueryResponse> Handle(GetHelloCustomerQuery request, CancellationToken cancellationToken)
{
var message = $"Hello, {request.Name}";
return ValueTask.FromResult(
new GetHelloCustomerQueryResponse(message)
);
}
}
Request
namespace ServiceDesk.Appeals.Domain.Queries;
internal sealed record GetHelloCustomerQuery(string Name) : IRequest<GetHelloCustomerQueryResponse>;
Response
namespace ServiceDesk.Appeals.Application.Queries;
internal sealed record GetHelloCustomerQueryResponse(string UserMessage);
Mediator.Send
namespace ServiceDesk.Appeals.Intermediate; /* indicated in the mediator's registration
builder.Services.AddMediator(options =>
options.Namespace = "ServiceDesk.Appeals.Intermediate"
);
*/
public sealed partial class Mediator : global::Mediator.IMediator, global::Mediator.ISender, global::Mediator.IPublisher
{
//...
/// <summary>
/// Send a message of type global::MinimalApi.WebApi.Intermediate.GetHelloCustomerQuery.
/// Throws <see cref="global::System.ArgumentNullException"/> if message is null.
/// </summary>
/// <param name="message">Incoming message</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Awaitable task</returns>
public global::System.Threading.Tasks.ValueTask<global::MinimalApi.WebApi.Intermediate.GetHelloCustomerQueryResponse> Send(
global::MinimalApi.WebApi.Intermediate.GetHelloCustomerQuery message,
global::System.Threading.CancellationToken cancellationToken = default
)
{
ThrowIfNull(message, nameof(message));
return _diCacheLazy.Value.Wrapper_For_MinimalApi_WebApi_Intermediate_GetHelloCustomerQuery.Handle(message, cancellationToken);
}
//...
}
Intended solution
Based on the access modifier of the object implementing the IRequest, set the necessary overload of the IMediator.Send method with the corresponding access modifier.
Over the years, I have come across many projects in which:
IRequest
) were stored in the Domain layerIMediator.Send
in the Presentation layer.All the listed objects have an internal access modifier, and the
.csproj
files specify theInternalsVisibleTo
tag up to the overlying layers.At the moment, in my current company, migration from Jimmy Bogart's MediatR to the current implementation is being discussed due to its advantages; however, the problem described above forces us, for the time being, to refrain from that.
Description of the problem
In cases where internal Handler, internal request, and internal response are used,
Inconsistent accessibility
occurs. The problem is that the generatedMediator.Send
method is public, when it's input parameter and return value are internal.Handler
Request
Response
Mediator.Send
Intended solution
Based on the access modifier of the object implementing the
IRequest
, set the necessary overload of theIMediator.Send
method with the corresponding access modifier.