Getting " InvalidOperationException: Error while validating the service descriptor 'ServiceType: MediatR.IRequestHandler`2"

Viewed 1424

I'm trying to implement refresh token in my api. The api is following CQRS+MediatR pattern and is using JWT for authentication. After adding a Handler to manage refresh call and a refresh token service I am getting the following error:

Inner Exception 1: InvalidOperationException: Error while validating the service descriptor 'ServiceType: MediatR.IRequestHandler`2 [UM.Business.Application.Token.Command.Update.UpdateTokenCommand,UM.Business.Application.Common.HandlerResult] Lifetime: Transient ImplementationType: UM.Business.Application.Token.Command.Update.UpdateTokenHandler':

Unable to resolve service for type 'UM.Infrastructure.Common.Configuration.AuthSettings' while attempting to activate 'UM.Business.Application.Token.Command.Update.UpdateTokenHandler'.

Inner Exception 2: InvalidOperationException: Unable to resolve service for type 'UM.Infrastructure.Common.Configuration.AuthSettings' while attempting to activate 'UM.Business.Application.Token.Command.Update.UpdateTokenHandler'.

My service is doing basic crud operations on the Refresh Token class.

First of all I added dependancy injection in a service module class,

service.AddTransient<IRefreshTokenService, RefreshTokenService>();

This is my controller end point,

        [Route("refresh")]
        [ProducesResponseType(typeof(LoginResponse), StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(IEnumerable<string>), StatusCodes.Status412PreconditionFailed)]
        [ProducesResponseType(typeof(string), StatusCodes.Status401Unauthorized)]
        [ProducesResponseType(typeof(ConfirmEmail), StatusCodes.Status400BadRequest)]
        [ProducesResponseType(typeof(AccountBlocked), StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Refresh([FromBody] UpdateRefreshTokenVM request, CancellationToken ct)
        {
            var refreshCommand= _mapper.Map<UpdateTokenCommand>(request);
            var authenticationResult = await _mediator.Send(refreshCommand, ct);
            if (authenticationResult == null)
                return Unauthorized();
            if (authenticationResult.IsSuccess)
                return Ok(authenticationResult.Result);
}

My UpdateRefreshTokenVM,

public class UpdateRefreshTokenVM
    {
        public string AccessToken { get; set; }
        public Core.Domain.Models.RefreshToken RefreshToken { get; set; } }

And UpdateTokenCommand,

public class UpdateTokenCommand : CommandBase<HandlerResult>
    {
        public string AccessToken { get; set; }
        public Core.Domain.Models.RefreshToken RefreshToken { get; set; }
    }

Handler getting called is this one,

public UpdateTokenHandler(IUserService userService, IMapper mapper, IRefreshTokenService refreshTokenService, IRoleService roleService, AuthSettings authSetting, IUserClaimsService userClaimService)
        {
            _userService = userService;
            _refreshTokenService = refreshTokenService;
            _userClaimService = userClaimService;
            _roleService = roleService;
            _authSetting = authSetting;
            _mapper = mapper;
        }

        public async Task<HandlerResult> Handle(UpdateTokenCommand request, CancellationToken cancellationToken)
        {
            var loginResponse = new HandlerResult();
            var userIdentity = await _userService.FindByEmailAsync(request.RefreshToken.User.Email);
            string accessToken = request.AccessToken;
            var refreshToken = request.RefreshToken;
            var principal = TokenGenerator.GetPrincipalFromExpiredToken(accessToken);
            var username = principal.Identity.Name; //this is mapped to the Name claim by default

            var refreshTokenFromDb =await _refreshTokenService.FindByUserId(refreshToken.User.Id);
            if (refreshTokenFromDb.RefreshTokenExpiryTime <= DateTime.Now)
            {
                return null;
            }

            if (refreshTokenFromDb == null || refreshTokenFromDb != refreshToken )
            {
                loginResponse.IsSuccess = false;
                loginResponse.ErrorMessage="Invalid client request";
                loginResponse.Result = null;
                return loginResponse;
            }

            var userClaims = await _userClaimService.GetClaims(userIdentity);
            var userRoles = await _roleService.GetUserRoles(userIdentity);
            var resultObject = TokenGenerator.GenerateJsonWebToken(userIdentity, userClaims, _authSetting, userRoles);
            //var newRefreshToken = TokenGenerator.GenerateRefreshToken();


            loginResponse.Result = resultObject;
            loginResponse.ErrorMessage = null;
            loginResponse.IsSuccess = true;

            //user.RefreshToken = newRefreshToken;
            //userContext.SaveChanges();

            // now save the token variable in db
            await _refreshTokenService.UpdateAsync(resultObject.RefreshToken);

            return loginResponse;
        }
    }

Following is the token generator used in the handler,


        internal static LoginResponse GenerateJsonWebToken(UM.Core.Domain.Models.User userInfo,IList<System.Security.Claims.Claim> userClaims, AuthSettings authSetting, IList<string> roleNames)
        {
            userClaims.Add(new System.Security.Claims.Claim(ClaimTypes.Email, userInfo.Email));
            userClaims.Add(new System.Security.Claims.Claim(ClaimTypes.NameIdentifier, userInfo.Id));
            userClaims.Add(new System.Security.Claims.Claim(ClaimTypes.Name, userInfo.NormalizedUserName));
            foreach(string name in roleNames)
            {
                userClaims.Add(new System.Security.Claims.Claim(ClaimTypes.Role, name));
            }
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authSetting.Key));

            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);

            var tokenDescriptor = new SecurityTokenDescriptor()
            {
                Issuer = authSetting.Issuer,
                Audience = authSetting.Audience,
                Subject = new ClaimsIdentity(userClaims),
                Expires = DateTime.UtcNow.AddMinutes(authSetting.ExpirationTimeInMin),
                SigningCredentials = credentials
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            var token = tokenHandler.CreateToken(tokenDescriptor);

            // Now generate refresh token
            var refreshToken = new RefreshToken
            {
                User = userInfo,
                //UserId = int.Parse(userInfo.Id),
                RefreshTokenString = GenerateRefreshToken(),
                RefreshTokenExpiryTime = DateTime.Now.AddDays(14)  // will change this later
            };

            var authenticationResponse = new LoginResponse
            {
                AccessToken = tokenHandler.WriteToken(token),
                RefreshToken = refreshToken,
                IsValid = true
            };
            return authenticationResponse;

        }

        public static string GenerateRefreshToken()
        {
            var randomNumber = new byte[32];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(randomNumber);
                return Convert.ToBase64String(randomNumber);
            }
        }

        public static ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
        {
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateAudience = false, //you might want to validate the audience and issuer depending on your use case
                ValidateIssuer = false,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@345")),
                ValidateLifetime = false //here we are saying that we don't care about the token's expiration date
            };
            var tokenHandler = new JwtSecurityTokenHandler();
            SecurityToken securityToken;
            var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken);
            var jwtSecurityToken = securityToken as JwtSecurityToken;
            if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
                throw new SecurityTokenException("Invalid token");
            return principal;
        }

Auth settings(which I didn't touch for this implementation)

 public class AuthSettings
    {
        public string Key { get; set; }
        public string Issuer { get; set; }
        public string Audience { get; set; }
        public int ExpirationTimeInMin { get; set; }
    }

And my login Response class,

public class LoginResponse
    {
        public string AccessToken { get; set; }
        public RefreshToken RefreshToken { get; set; }
        public bool IsValid { get; set; }
        public bool VerificationRequired { get; set; }
        public bool TwoFactorRequired { get; set; }

        public LoginResponse()
        {
            RefreshToken = new RefreshToken();
        }
    }
0 Answers
Related