'notification does not implement $INotification C#
I have a multi-tenancy project using mediator and CQRS, for some reason my CRUD from order request are returning this error, I already try refactor my handler sometimes including by removing the cancelation token from the request handler class, but don´t work.
All the http methods return exactly the same error but in differently handlers, we are using Azure Service Bus for the queue.
Any tips? Thanks!
Error:
System.Exception
---> System.ArgumentException: notification does not implement $INotification
at MediatR.Mediator.Publish(Object notification, CancellationToken cancellationToken)
at Project.RequestHandler.MarketPlace.Order.OrderGetRequestHandler.Handle(OrderGetRequest request, CancellationToken cancellationToken) in C:\git\Project\project-apis\03.Services\Project.RequestHandler\MarketPlace\Order\OrderGetRequestHandler.cs:line 27
at MediatR.Internal.RequestHandlerWrapperImpl`2.<>c__DisplayClass1_0.<Handle>g__Handler|0()
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at Project.MarketPlaceAPI.Controllers.OrderController.Get() in C:\git\Project\project-apis\01.Application\Project.MarketPlaceAPI\Controllers\OrderController.cs:line 28
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Project.Infra.CrossCutting.Middlewares.IPFilterMiddleWare.Invoke(HttpContext context, IOptions`1 applicationOptionsAccessor, ILogger`1 logger) in C:\git\Project\project-apis\04.Infra\04.02.CrossCutting\Project.Infra.CrossCutting\Middlewares\IPFilterMiddleware.cs:line 37
--- End of inner exception stack trace ---
at Project.Infra.CrossCutting.Middlewares.IPFilterMiddleWare.Invoke(HttpContext context, IOptions`1 applicationOptionsAccessor, ILogger`1 logger) in C:\git\Project\project-apis\04.Infra\04.02.CrossCutting\Project.Infra.CrossCutting\Middlewares\IPFilterMiddleware.cs:line 82
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Cache-Control: no-cache
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip, deflate, br
Authorization: Bearer <REMOVED SECURITY TOKEN>
Host: localhost:<PORT>
User-Agent: PostmanRuntime/7.29.0
Postman-Token: <TOKEN>
Entity:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
#nullable disable
namespace Project.Domain.Entities
{
public class Order : UpdatedEntity
{
public Order() { }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OrderId { get; init; }
[ForeignKey("Tenant")]
public int TenantId {get;set;}
[ForeignKey("TargetTenant")]
public int TargetTenantId {get;set;}
public virtual Tenant Tenant { get; set; }
public virtual Tenant TargetTenant { get; set; }
}
}
OrderGetDTO:
using System;
using Project.Domain.Entities;
namespace Project.Domain.DTO.MarketPlace.Order
{
public class OrderGetDTO
{
public int OrderId { get; set; }
public int TenantId { get; set; }
public int TargetTenantId { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
}
OrderGetResponse:
using System.Collections.Generic;
using Project.Domain.DTO.MarketPlace.Order;
using Project.Domain.Responses.Generics;
using MediatR;
namespace Project.Domain.Responses.MarketPlace.Order
{
public class OrderGetResponse : RowsResponse<OrderGetDTO>
, INotification
{
public OrderGetResponse (bool success, string message) : base(success, message) { }
public OrderGetResponse (IEnumerable<OrderGetDTO> rows) : base(rows) { }
}
}
OrderGetRequest:
using Project.Domain.Interfaces.Requests;
using Project.Domain.Responses.MarketPlace.Order;
using MediatR;
namespace Project.Domain.Requests.MarketPlace.Order
{
public class OrderGetRequest : BaseListTenantUserRequest
, IRequest<OrderGetResponse>
, ITargetTenantRequest
{
public int OrderId { get; set; }
public int TargetTenantId {get;set;}
}
}
IOrderGetRepository:
using System.Threading.Tasks;
using Project.Domain.Requests.MarketPlace.Order;
using Project.Domain.Responses.MarketPlace.Order;
namespace Project.Domain.Interfaces.Repository.MarketPlace.Order
{
public interface IOrderGetRepository
{
Task<OrderGetResponse> Handle(OrderGetRequest request);
}
}
OrderGetRequestHandler:
using MediatR;
using System.Threading;
using System.Threading.Tasks;
using Project.Domain.Interfaces.Repository.MarketPlace.Order;
using Project.Domain.Requests.MarketPlace.Order;
using Project.Domain.Responses.MarketPlace.Order;
namespace Project.RequestHandler.MarketPlace.Order
{
public class OrderGetRequestHandler : IRequestHandler< OrderGetRequest
, OrderGetResponse>
{
private readonly IOrderGetRepository _repository;
private readonly IMediator _mediator;
public OrderGetRequestHandler( IOrderGetRepository repository,
IMediator mediator)
{
_repository = repository;
_mediator = mediator;
}
public Task<OrderGetResponse> Handle( OrderGetRequest request
, CancellationToken cancellationToken)
{
var returnValue = _repository.Handle(request);
_mediator.Publish(returnValue, cancellationToken);
return returnValue;
}
}
}
OrderGetRepository:
using System.Linq;
using Project.Infra.Data.Context;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using Project.Domain.DTO.MarketPlace.Order;
using Project.Domain.Interfaces.Repository.Tenants;
using Project.Domain.Interfaces.Repository.MarketPlace.Order;
using Project.Domain.Requests.MarketPlace.Order;
using Project.Domain.Responses.MarketPlace.Order;
namespace Project.Infra.Data.Repository.MarketPlace.Order
{
public class OrderGetRepository : IOrderGetRepository
{
private readonly ProjectContext _context;
private readonly ITenantRepository _tenantRepository;
public OrderGetRepository( ProjectContext context
, ITenantRepository tenantRepository)
{
_context = context;
_tenantRepository = tenantRepository;
}
public async Task<OrderGetResponse> Handle(OrderGetRequest request)
{
var tenantRecord = await _tenantRepository.Handle(request);
if (tenantRecord == null)
{
return new OrderGetResponse(false, "Tenant not found") {
IsNotFound = true
};
}
request.Query = string.IsNullOrEmpty(request.Query) ||
request.Query.ToLower().Equals("[null]") ? string.Empty :
request.Query.ToLower();
return new OrderGetResponse ((
await _context.Orders
.Where(r=> r.TenantId.Equals(tenantRecord.TenantId) &&
r.OrderId.Equals(request.OrderId))
.Select(r => new OrderGetDTO() {
OrderId = r.OrderId,
TenantId = r.TenantId,
TargetTenantId = r.TargetTenantId,
CreatedAt = r.CreatedAt,
UpdatedAt = r.UpdatedAt ?? r.CreatedAt
})
.ToListAsync()));
}
}
}
Order Controller:
using MediatR;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Project.Infra.Shared.Controllers;
using Microsoft.AspNetCore.Authorization;
using Project.Domain.Requests.MarketPlace.Order;
using Project.Domain.Responses.MarketPlace.Order;
namespace Project.MarketPlaceAPI.Controllers
{
[ApiController]
[Authorize]
[Route("api/v2/[controller]")]
public class OrderController : BaseApiController
{
private readonly IMediator _mediator;
public OrderController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(OrderGetResponse))]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Get()
{
return ProcessResponse(await _mediator.Send(new OrderGetRequest()
{
TenantId = TenantId,
UserId = UserId
}));
}
[HttpGet]
[Route("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(OrderGetResponse))]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Get(int id)
{
return ProcessResponse(await _mediator.Send(new OrderGetRequest()
{
TenantId = TenantId,
UserId = UserId,
OrderId = id
}));
}
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(OrderGetResponse))]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Post([FromBody] OrderGetRequest request)
{
request.TenantId = TenantId;
request.UserId = UserId;
return ProcessResponse(await _mediator.Send(request));
}
[HttpPut]
[Route("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(OrderGetResponse))]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Put([FromBody] OrderGetRequest request
, int id)
{
request.TenantId = TenantId;
request.UserId = UserId;
request.OrderId = id;
return ProcessResponse(await _mediator.Send(request));
}
[HttpPatch]
[Route("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(OrderGetResponse))]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Patch([FromBody] OrderGetRequest request
, int id)
{
request.TenantId = TenantId;
request.UserId = UserId;
request.OrderId = id;
return ProcessResponse(await _mediator.Send(request));
}
[HttpDelete]
[Route("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(OrderDeleteResponse))]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Delete([FromBody] OrderDeleteRequest request
, int id)
{
request.TenantId = TenantId;
request.UserId = UserId;
request.OrderId = id;
return ProcessResponse(await _mediator.Send(request));
}
}
}
Solution 1:[1]
I was googling for a solution to the same error: notification does not implement $INotification
Couldn't find anything, but figured out the problem in my code, so perhaps you're dealing with the same issue. I was calling:
_mediator.Publish(MyRequest...)
when in fact I should've been calling
_mediator.Send(MyRequest...)
You can only Publish
Notifications
. You can only Send
Requests
. The error is complaining about trying to Publish
an object that's not a Notification
. Try changing the following line from Publish
to Send
and see if it works, or verify that the object you are trying to Publish
is actually a notification (it needs to implement INotification
interface:
_mediator.Publish(returnValue, cancellationToken);
EDIT:
I took another look at your code and I believe the issue is that you are not awaiting
the returnValue in the first line below:
var returnValue = _repository.Handle(request);
_mediator.Publish(returnValue, cancellationToken);
That causes the returnValue to be of Task<INotification>
which is not what the Publish function below expects. You should do the following instead:
var returnValue = await _repository.Handle(request);
await _mediator.Publish(returnValue, cancellationToken);
You will also need to make the function signature async
for it to compile:
public async Task<OrderGetResponse> Handle( OrderGetRequest request...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |