The company I am working with has multiple developers. We are all fairly new to MediatR, and we currently have about 200 "slices" running correctly on our API.
The project is ASP.NET Core with .NET 7.0.
In the API's Program.cs, we have using MediatR; at the top and NuGet shows we are running Version 12.2.0 by Jimmy Bogard.
builder.Services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssemblies(typeof(Program).Assembly);
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationPipelineBehavior<,>));
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(TransactionPipelineBehavior<,>));
});
I have written a new API on the server called AddPhoneNumber that the Web Client hits fine, the request is generated, but the response from _mediator.Send(request) is always NULL - so it fails.
public async Task<IActionResult> AddPhoneNumber(long applicantId, string dialNumber, int phoneTypeId)
{
var request = new AddPhoneNumber.Request()
{
ApplicantId = applicantId,
DialNumber = dialNumber,
PhoneTypeId = phoneTypeId,
};
var response = await _mediator.Send(request);
return response.PhoneNumberId > 0 ? Ok(response) : NotFound(response);
}
But the way I wrote my Handler, it should never return a NULL value.
The class is below because I may have written something wrong. I have a breakpoint set in Visual Studio 2022 at the method Handle(Request request, CancellationToken cancellationToken), but it never even gets called.
public class AddPhoneNumber
{
public class Request : IRequest<Response>
{
public long ApplicantId { get; set; }
public string DialNumber { get; set; } = string.Empty;
public int PhoneTypeId { get; set; }
}
public class Response
{
public long PhoneNumberId { get; set; }
}
#region validators
public class Validator : AbstractValidator<Request>, IRequestValidator
{
public Validator()
{
RuleFor(r => r.ApplicantId).GreaterThan(0);
}
}
public class Validator2 : AbstractValidator<Request>, IRequestValidator
{
public Validator2()
{
RuleFor(r => r.PhoneTypeId).GreaterThan(0);
RuleFor(r => r.DialNumber).NotNull().NotEmpty();
}
}
public class DomainValidator : AbstractValidator<Request>, IDomainValidator
{
public DomainValidator(APIContext db)
{
//check Database
RuleFor(r => r.ApplicantId).MustAsync(async (id, cancellation) =>
{
var result = await db.Applicants.FindAsync(id, cancellation);
return result != null ? true : false;
}).WithMessage("Applicant is invalid");
RuleFor(r => r.PhoneTypeId).MustAsync(async (id, cancellation) =>
{
var result = true;
if (id != 0)
{
var lookup = await db.Lookups.FirstOrDefaultAsync(l => l.LookupId == id && !l.IsDeleted, cancellation);
result = (lookup != null);
}
return result;
}).WithMessage("Phone Type is invalid");
RuleFor(r => r.DialNumber).MustAsync(async (obj, id, cancellation) =>
{
var result = true;
if (!string.IsNullOrEmpty(obj.DialNumber))
{
var any = await db.PhoneNumbers.AnyAsync(p =>
p.ApplicantId == obj.ApplicantId &&
p.PhoneTypeId == obj.PhoneTypeId &&
p.DialNumber == obj.DialNumber);
result = !any;
}
return result;
}).WithMessage("Phone Number already exists for Applicant");
}
}
#endregion
#region handler
public class Handler : IRequestHandler<Request, Response>
{
private readonly APIContext _db;
public Handler(APIContext db)
{
_db = db;
}
public async Task<Response> Handle(Request request, CancellationToken cancellationToken)
{
var response = new Response();
var phoneNumbers = await _db.PhoneNumbers.Where(x => x.ApplicantId == request.ApplicantId).ToListAsync();
var applicant = await _db.Applicants.FirstOrDefaultAsync(x => x.ApplicantId == request.ApplicantId);
if (applicant != null)
{
var exactPhone = phoneNumbers.FirstOrDefault(x => x.DialNumber == request.DialNumber && x.PhoneTypeId == request.PhoneTypeId);
if (exactPhone != null)
{
response.PhoneNumberId = exactPhone.PhoneNumberId;
}
else
{
var phone = new AM.Data.Models.PhoneNumber()
{
PhoneTypeId = request.PhoneTypeId,
DialNumber = request.DialNumber,
ApplicantId = request.ApplicantId,
};
await _db.PhoneNumbers.AddAsync(phone, cancellationToken);
await _db.SaveChangesAsync(cancellationToken);
response.PhoneNumberId = phone.PhoneNumberId;
}
}
return response;
}
}
#endregion
};