I have an API whith a Controller called Token Controller which validates a user and gives a token.
The problem is it was working just fine until now, I didn't change anything so I have no idea what happened. Please help.
Here is the code of my Token controller
public TokenController(IConfiguration configuration, ICrUserInfoService crUserInfoService, IPasswordService passwordService)
{
_configuration = configuration;
_crUserInfoService = crUserInfoService;
_passwordService = passwordService;
}
[HttpPost]
public async Task<IActionResult> Authentication(UserLogin login)
{
//if it is a valid user
var validation = await IsValidUser(login);
if (validation.Item1)
{
var token = GenerateToken(validation.Item2);
return Ok(new { token });
}
return NotFound("Unvalid User");
}
private async Task<(bool, CrUserInfo)> IsValidUser(UserLogin login)
{
var user = await _crUserInfoService.GetLoginByCredentials(login);
bool isValid;
if (user == null)
{
isValid = false;
}
else
{
isValid = _passwordService.Check(user.Password, login.Password);
}
return (isValid, user);
}
private string GenerateToken(CrUserInfo user)
{
//Header
var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Authentication:SecretKey"]));
var signingCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256);
var header = new JwtHeader(signingCredentials);
//Claims
var claims = new[]
{
new Claim(ClaimTypes.Name, user.Username),
new Claim("User", user.Displayname),
new Claim(ClaimTypes.Role, user.Role.ToString()),
};
//Payload
var payload = new JwtPayload
(
_configuration["Authentication:Issuer"],
_configuration["Authentication:Audience"],
claims,
DateTime.Now,
DateTime.Now.AddMinutes(30)
);
var token = new JwtSecurityToken(header, payload);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
As I said it was working just fine till now and here is the error
System.InvalidCastException: Can't convert VarChar to Int32
at MySqlConnector.Core.Row.GetInt32(Int32 ordinal) in /_/src/MySqlConnector/Core/Row.cs:line 223
at MySqlConnector.MySqlDataReader.GetInt32(Int32 ordinal) in /_/src/MySqlConnector/MySqlDataReader.cs:line 242
at lambda_method23(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
at Crijoya.Infrastructure.Repositories.CrUserInfoRepository.GetLoginByCredentials(UserLogin login) in C:\Users\USER\source\repos\Api Crijoya\Crijoya.Data\Repositories\CrUserInfoRepository.cs:line 15
at Crijoya.Core.Services.CrUserInfoService.GetLoginByCredentials(UserLogin userLogin) in C:\Users\USER\source\repos\Api Crijoya\Crijoya.Model\Services\CrUserInfoService.cs:line 20
at Api_Crijoya.Controllers.TokenController.IsValidUser(UserLogin login) in C:\Users\USER\source\repos\Api Crijoya\Api Crijoya\Controllers\TokenController.cs:line 51
at Api_Crijoya.Controllers.TokenController.Authentication(UserLogin login) in C:\Users\USER\source\repos\Api Crijoya\Api Crijoya\Controllers\TokenController.cs:line 40
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>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ExceptionContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
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__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
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)
I am not sure the issue is in the code as I said it was working minutes ago and giving a correct Token. Please help I don't know how to approach this.
EDIT:
The repository of my entity CrUserInfo which contains the user and password
public CrUserInfoRepository(db_crijoyaContext context) : base(context) { }
public async Task<CrUserInfo> GetLoginByCredentials(UserLogin login)
{
return await _entities.FirstOrDefaultAsync(x => x.Username == login.User);
}
Here is my entity CrUserInfo
public partial class CrUserInfo : BaseEntity
{
// public int IdUserInfo { get; set; }
public int IdUser { get; set; }
public string Displayname { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public RoleType Role { get; set; }
public virtual CrUser IdUserNavigation { get; set; }
}
My Dto entity
public class CrUserInfoDto
{
public int Id { get; set; }
public int IdUser { get; set; }
public string Displayname { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public RoleType Role { get; set; }
}
My database
Here is the script
CREATE TABLE `cr_userInfo` (
`id_userInfo` int(6) unsigned NOT NULL AUTO_INCREMENT,
`id_user` int(6) unsigned NOT NULL,
`displayname` varchar(50) NOT NULL,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
`role` varchar(30) NOT NULL,
PRIMARY KEY (`id_userInfo`) USING BTREE,
UNIQUE KEY `id_user` (`id_user`) USING BTREE,
CONSTRAINT `cr_userInfo_ibfk_1` FOREIGN KEY (`id_user`) REFERENCES `cr_user` (`id_user`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
This is what it did before it stopped working
ONMODELCREATING CODE:
modelBuilder.Entity<CrUser>(entity =>
{
entity.HasKey(e => e.Id)
.HasName("PRIMARY");
entity.ToTable("cr_user");
entity.HasIndex(e => e.IdCompany, "company");
entity.Property(e => e.Id)
.HasColumnType("uint(6) unsigned")
.HasColumnName("id_user");
entity.Property(e => e.Active)
.HasColumnType("tinyint(1) unsigned")
.HasColumnName("active")
.HasDefaultValueSql("'1'");
entity.Property(e => e.IdCompany)
.HasColumnType("int(6) unsigned")
.HasColumnName("id_company");
entity.Property(e => e.Warehouse)
.HasColumnType("int(6)")
.HasColumnName("warehouse")
.HasDefaultValueSql("'NULL'");
entity.HasOne(d => d.IdCompanyNavigation)
.WithMany(p => p.CrUsers)
.HasForeignKey(d => d.IdCompany)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("cr_user_ibfk_1");
});
modelBuilder.Entity<CrUserInfo>(entity =>
{
entity.HasKey(e => e.Id)
.HasName("PRIMARY");
entity.ToTable("cr_userInfo");
entity.HasIndex(e => e.IdUser, "id_user")
.IsUnique();
entity.Property(e => e.Id)
.HasColumnType("uint(6) unsigned")
.HasColumnName("id_userInfo");
entity.Property(e => e.Displayname)
.IsRequired()
.HasMaxLength(50)
.HasColumnName("displayname");
entity.Property(e => e.IdUser)
.HasColumnType("int(6) unsigned")
.HasColumnName("id_user");
entity.Property(e => e.Password)
.IsRequired()
.HasMaxLength(255)
.HasColumnName("password");
entity.Property(e => e.Role)
.IsRequired()
.HasMaxLength(30)
.HasColumnName("role");
entity.Property(e => e.Username)
.IsRequired()
.HasMaxLength(50)
.HasColumnName("username");
entity.HasOne(d => d.IdUserNavigation)
.WithOne(p => p.CrUserInfo)
.HasForeignKey<CrUserInfo>(d => d.IdUser)
.HasConstraintName("cr_userInfo_ibfk_1");
});
CodePudding user response:
You will have to update your OnModelCreating
code from this:
entity.Property(e => e.Role)
.IsRequired()
.HasMaxLength(30)
.HasColumnName("role");
To indicate that it should be string
:
entity.Property(e => e.Role)
.IsRequired()
.HasMaxLength(30)
.HasColumnName("role")
.HasConversion<string>();
According to the documentation, this should automatically convert between the database varchar
type and the RoleType
in C#:
For example, enum to string conversions are used as an example above, but EF Core will actually do this automatically when the provider type is configured as string using the generic type of
HasConversion
: