Error while validating the service descriptor 'ServiceType: MediatR.IRequestHandler - cqrs

I implement JwtService from IJwtService at the Infrastructure layer
IJwtService declare at the Application layer
and
I implement IdentityService from IIdentityService at the Infrastructure layer
I register both at infrastructure dependency injection like
services.AddTransient< IJwtService,JwtService>();
services.AddTransient<IIdentityService,IdentityService>();
Then I implement LoginQueryHandler implement from : IRequestHandler<LoginViewModel, LoginDto>
within LoginQueryHandler() i inject IIdentityService and IJwtService
I register Mediator at Application Layer as this
services.AddMediatR(Assembly.GetExecutingAssembly());
using mediator I send a request to LoginQuery Handler
public async Task Login([FromBody] LoginViewModel model)
{
return await Mediator.Send(model);
}
This is LoginQueryHandler Class
public class LoginViewModel: IRequest<LoginDto>
{
public string Email { get; set; }
public string Password { get; set; }
}
public class LoginQueryHandler : IRequestHandler<LoginViewModel, LoginDto>
{
private readonly IIdentityService _identityService;
private readonly IJwtService _jwtService;
public LoginQueryHandler(IIdentityService identityService,IJwtService jwtService)
{
_identityService=identityService;
_jwtService=jwtService;
}
public async Task<LoginDto> Handle(LoginViewModel request, CancellationToken cancellationToken)
{
try
{
var user = await _identityService.FindByEmailAsync(request.Email);
// codes....
return new LoginDto();
}
catch (Exception ex)
{
throw ex;
}
}
}
but it throws the following error
System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: MediatR.IRequestHandler`2[Application.Login.Queries.LoginViewModel,Application.Login.Queries.LoginDto] Lifetime: Transient ImplementationType: Application.Login.Queries.LoginQueryHandler': Unable to resolve service for type 'TechneTravel.Infrastructure.Services.JwtService' while attempting to activate 'Newproject.Infrastructure.Identity.IdentityService'.
---> System.InvalidOperationException: Unable to resolve service for type 'Newproject.Infrastructure.Services.JwtService' while attempting to activate 'Newproject.Infrastructure.Identity.IdentityService'
Then I tried three ways to register Request Handler at the Application layer as bellow
services.AddTransient(typeof(IRequestHandler<LoginViewModel, LoginDto>), typeof(LoginQueryHandler));
services.AddTransient<IRequestHandler<LoginViewModel, LoginDto>, LoginQueryHandler>();
services.AddTransient(typeof(LoginQueryHandler));
but not solved

Based on your error message it seems that you are trying to resolve JwtService in your Newproject.Infrastructure.Identity.IdentityService but you have only interface registration:
services.AddTransient<IJwtService, JwtService>();
So either change your IdentityService to accept IJwtService instead of JwtService (I would say that it is far better option) or change/add registration to inject using concrete class:
services.AddTransient<JwtService>();

Related

An error occurred while accessing the Microsoft.Extensions.Hosting services. After Adding ASP.NET identity

I have DataContext and StartUp class in different projects and to add a new migration in Data project I used the below command:
dotnet ef migrations add IdentityAdded -s ..\API\API.csproj
And here is project structure:
I just added ASP.Net Core Identity to the project based on .Net 5 and configured it as below:
public class DataContext : IdentityDbContext<AppUser, AppRole, int,
IdentityUserClaim<int>, AppUserRole, IdentityUserLogin<int>,
IdentityRoleClaim<int>, IdentityUserToken<int>>
{
public DataContext(DbContextOptions<DataContext> options) : base(options)
{
ChangeTracker.LazyLoadingEnabled = false;
}
... DbSets
... protected override void OnModelCreating(ModelBuilder modelBuilder)
{ ... }
}
IdentityServiceExtension.cs:
public static class IdentityServiceExtension
{
public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddIdentityCore<AppUser>(opt =>
{
opt.Password.RequireNonAlphanumeric = false;
})
.AddRoles<AppRole>()
.AddRoleManager<RoleManager<AppRole>>()
.AddSignInManager<SignInManager<AppUser>>()
.AddRoleValidator<RoleValidator<AppUser>>()
.AddEntityFrameworkStores<DataContext>();
}
}
I just inherited some classes such as AppUser, AppRole and AppUserRole from Identity Classes like this:
public class AppRole : IdentityRole<int>
{
public ICollection<AppUserRole> TheUserRolesList { get; set; }
}
After running the migration I get the following error:
An error occurred while accessing the Microsoft.Extensions.Hosting services. Continuing without the application service provider. Error: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Microsoft.AspNetCore.Identity.RoleManager1[Core.Models.Entities.User.AppRole] Lifetime: Scoped ImplementationType: Microsoft.AspNetCore.Identity.RoleManager1[Core.Models.Entities.User.AppRole]': Implementation type 'Microsoft.AspNetCore.Identity.RoleValidator1[Core.Models.Entities.User.AppUser]' can't be converted to service type 'Microsoft.AspNetCore.Identity.IRoleValidator1[Core.Models.Entities.User.AppRole]')
What's wrong with this implementation?
You didn't register properly, instead of:
.AddRoleValidator<RoleValidator<AppUser>>()
add:
.AddRoleValidator<RoleValidator<AppRole>>()
Your error points out that it can't instantiate Microsoft.AspNetCore.Identity.RoleValidator with the Core.Models.Entities.User.AppUser, instead it requires Core.Models.Entities.User.AppRole.

Using a DB context factory in Blazor server

I'm having a few issues setting up the EF database connection for my server side Blazor app. It was working with the standard DbContext setup until I noticed a few issues with connections not closing properly due to the nature of Blazor using the same context throughout. My research led me to look at DbContextFactory, but the interface IDbContextFactory is now deprecated in favour of IDesignTimeDbContextFactory.
I've set up a class to implement the interface:
public class FIS2ContextFactory : IDesignTimeDbContextFactory<FIS2_DbContext>
{
private readonly DbContextOptions<FIS2_FranklinContext_AutoGenerated> options;
public FIS2ContextFactory(DbContextOptions<FIS2_FranklinContext_AutoGenerated> contextOptions)
{
options = contextOptions;
}
public FIS2_DbContext CreateDbContext(string[] args)
{
return new FIS2_DbContext(options);
}
}
The DbContext I'm wanting to use is this, which inherits and expands on the DbContext generated by EF Power Tools:
public partial class FIS2_DbContext : FIS2_FranklinContext_AutoGenerated
{
public FIS2_DbContext()
{
}
public FIS2_DbContext(DbContextOptions<FIS2_FranklinContext_AutoGenerated> options) : base(options)
{
}
public virtual DbSet<StudentBasicDetailsWithCurrentTg> StudentBasicDetailsWithCurrentTgs { get; set; }
public virtual DbSet<CurriculumSearchBasicDetails> CurriculumSearchBasicDetails { get; set; }
public virtual DbSet<StudentAllEnrolments> StudentAllEnrolments { get; set; }
}
In my startup.cs I have it set up like this in the ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextFactory<FIS2_DbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("FIS2")));
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<IFileService, FileService>();
services.AddScoped<IEmailService, EmailService>();
services.AddScoped<ITimetableService, TimetableService>();
services.AddScoped<ICurriculumService, CurriculumServiceEf>();
services.AddScoped<IStudentService, StudentServiceEf>();
services.AddScoped<ICollectionService, CollectionsServiceEf>();
services.AddHttpContextAccessor();
services.AddHttpClient();
services.AddAuthenticationCore();
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddAuthorization();
services.AddSyncfusionBlazor();
services.AddScoped<SessionState>();
}
My issue is that when it gets to setting up the services that utilise this database connection, I am met with this error message in the program.cs:
Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: DataLibrary.Data.Interfaces.ITimetableService Lifetime: Scoped ImplementationType: DataLibrary.Data.BusinessLayer.TimetableService': Unable to resolve service for type 'DataLibrary.Models.FIS2ContextFactory' while attempting to activate 'DataLibrary.Data.BusinessLayer.TimetableService'.) (Error while validating the service descriptor 'ServiceType: DataLibrary.Data.Interfaces.ICurriculumService Lifetime: Scoped ImplementationType: DataLibrary.Data.BusinessLayer.CurriculumServiceEf': Unable to resolve service for type 'DataLibrary.Models.FIS2ContextFactory' while attempting to activate 'DataLibrary.Data.BusinessLayer.CurriculumServiceEf'.) (Error while validating the service descriptor 'ServiceType: DataLibrary.Data.Interfaces.IStudentService Lifetime: Scoped ImplementationType: DataLibrary.Data.BusinessLayer.StudentServiceEf': Unable to resolve service for type 'DataLibrary.Models.FIS2ContextFactory' while attempting to activate 'DataLibrary.Data.BusinessLayer.StudentServiceEf'.) (Error while validating the service descriptor 'ServiceType: DataLibrary.Data.Interfaces.ICollectionService Lifetime: Scoped ImplementationType: DataLibrary.Data.BusinessLayer.CollectionsServiceEf': Unable to resolve service for type 'DataLibrary.Models.FIS2ContextFactory' while attempting to activate 'DataLibrary.Data.BusinessLayer.CollectionsServiceEf'.)
For reference, here is an example of how the TimetableService is set up (the others are instantiated in the same way):
using DataLibrary.Data.Interfaces;
using DataLibrary.Models;
using DataLibrary.Models.timetable;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace DataLibrary.Data.BusinessLayer
{
public class TimetableService : ITimetableService
{
private FIS2ContextFactory _contextFactory;
public TimetableService(FIS2ContextFactory db)
{
_contextFactory = db;
}
public async Task<List<spGetHolidaysBetweenDatesResult>> GetHolidaysBetweenDatesAsync(DateTime startDate, DateTime endDate)
{
string[] args = { "" };
var _db = _contextFactory.CreateDbContext(args);
var procedures = _db.Procedures;
return await procedures.spGetHolidaysBetweenDatesAsync(startDate, endDate);
}
public async Task<List<PeriodsBetweenDates>> GetPeriodsBetweenDatesAsync(DateTime startDate, DateTime endDate)
{
string[] args = { "" };
var _db = _contextFactory.CreateDbContext(args);
var procedures = _db.Procedures;
var toReturn = new List<PeriodsBetweenDates>();
var results = await procedures.spGetPeriodsBetweenDatesAsync(startDate, endDate);
foreach (var item in results)
{
toReturn.Add(new PeriodsBetweenDates(item.Date, item.Timetable, item.BlockCode, item.StartTime, item.EndTime));
}
return toReturn;
}
public async Task<List<StudentTimetable>> GetStudentTimetableAsync(DateTime startDate, DateTime endDate, string studentID)
{
string[] args = { "" };
var _db = _contextFactory.CreateDbContext(args);
var procedures = _db.Procedures;
var results = await procedures.spGetStudentTimetableAsync(startDate, endDate, studentID);
List<StudentTimetable> studentTimetables = new List<StudentTimetable>();
foreach (var item in results)
{
studentTimetables.Add(JsonConvert.DeserializeObject<StudentTimetable>(item.timetable));
}
return studentTimetables;
}
}
}
Is it because I'm using the wrong method to create the context factory in the startup, or is it something later on that I've got wrong?
If you want to resolve a specific factory type, you must register with this overload, AddDbContextFactory<TContext,TFactory> documented here:
This overload allows a specific implementation of
IDbContextFactory to be registered instead of using the
default factory shipped with EF Core.
so
services.AddDbContextFactory<FIS2_DbContext,FIS2ContextFactory>(options => options.UseSqlServer(Configuration.GetConnectionString("FIS2")));

Spring Transactions - How to access to entity saved in parent transaction

consider following model:
#Service
public class TripServiceImpl implements TripService {
#Autowired
private EventService eventService;
#Autowired
private CalendarService calendarService;
#Transactional
public void processTrip(TripDto dto) {
EventDto event = eventService.findByTripId(dto).orElseGet(() -> eventService.createByTrip(dto));
dto.getMembers().forEach(memberCode -> {
try {
calendarService.createReminder(event.getId(), memberCode);
} catch (Exception ex) {}
});
// rest logic
}
}
This is how createReminder method looks like:
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void createReminder(Long eventId, String memberCode) {
Optiona<Event> eventRepository.findById(eventId); // this returns Optional.empty()
...
}
In our trip service we find or create event for given trip if no exists, and add reminders to calendars of members from that trip. Method for creating reminders we need as new transaction to ensure, if that method failed with exception, don't rollback all changes. This transaction propagation unfortunately can't find entity which was saved in parent transactional method. Can you tell me how to fix it? Thank you.

How to remove/handle irrelevant or bad sort parameters from http url using Pageable interface in spring boot?

How to remove/handle irrelevant or bad sort parameters from http url using Pageable interface in spring boot?
For e.g. I have a query like
http://localhost:8080/all?sort=firstName,asc&sort=nosuchfield,asc
How can I handle or remove the irrelevant field "nosuchfield"?
Also, how can I limit sort parameters in URL?
If the sorting field doesn't present in the database then below exception will be thrown by Spring JPA.
org.springframework.data.mapping.PropertyReferenceException: No property nosuchfield found for type <TYPE>!
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:94)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:382)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:358)
However, the exception can be handled using various types. Ultimately, you can just log it or transform it into any custom exception. As per my requirement, I have transformed it into a custom exception.
Using AOP
#Aspect
#Component
public class UnKnownColumnSortingExceptionHandler {
#AfterThrowing(pointcut = "execution(* com.repositorypackage.*.*(..))", throwing = "exception")
public void executeWhenExceptionThrowninRepository(JoinPoint jp, Throwable ex) {
if (ex instanceof PropertyReferenceException) {
throw new CustomException("Invalid Database operation");
}
}
}
Using #ControllerAdvice(Exception handling in Application wise)
#ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
public GlobalExceptionHandler() {}
#ExceptionHandler({PropertyReferenceException.class})
public ResponseEntity<Void> handleAllExceptions(Exception ex, WebRequest req) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Exception handling in Controller wise
Add the below piece of code to your controller
#ExceptionHandler({PropertyReferenceException.class})
public ResponseEntity<Void> handleAllExceptions(Exception ex, WebRequest req)
{
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}

Repository autowired returning null

I want to make a application with Spring boot on back-end and Swing on front-end. I need to use a repository autowired on my service class, how to make it when i need to instantiate the service class?
I already tried change the repository to BeanFactory, tried to change the location of the files but i can't escape! I need to instantiate the Service class and autowired doesn't work with this.
I have a Model called Permission.
Repository (PermissionRepository.java):
#Repository
public interface PermissionRepository extends JpaRepository<Permission, Long>{
Optional<Permission> findByDescription(String description);
}
Service (PermissionService.java):
#Autowired
BeanFactory beanFactory;
public List<Permission> loadAll() {
return this.beanFactory.getBean(PermissionRepository.class).findAll();
}
Use (BasicOperations.java):
public static void initialPermission() {
try {
if (new PermissionService().loadAll().isEmpty()) {
//logics
}
} catch(Exception e) {
...
}
}
I expect a List, java.util.List but, the error is a nullPointer on my autowired repository
Stack:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at com.riTrap.service.PermissionService.loadAll(PermissionService.java:20)
You should use autowired instead of new PermissionService. You use loadAll to check if the database contains elements. If the database is big, this approach can damage your application. Suggestion : use count instead
#Service
public class PermissionService {
#Autowired
PermissionRepository permissionRepository;
public List<Permission> loadAll() {
return permissionRepository.findAll();
}
public boolean isEmpty() {
return permissionRepository.count() == 0L;
}
}
If you need to initialize the bean before usage, you can use the constructor :
#Service
public class BasicOperations {
#Autowired
public BasicOperations(PermissionService permissionService){
if(permissionService.isEmpty()){
//DO STUFF
}
}
}