Reputation: 463
I am trying to implement aspnetcore identity without entity framework and using direct connection to SQL Server and I created identityuser, userstore and usertable so far. I am trying to register a new user using the default Register View and using default Accounts controller's Register method which calls _usermanager.CreateAsync and it always throws error what ever the username is as User name '' is invalid, can only contain letters or digits it says user name '' it is not saying the username that I entered but displays '', is that right?
Configure services in Startup.cs looks as below
public void ConfigureServices(IServiceCollection services)
{
var roleStore = new RoleStore();
var userPrincipalFactory = new ExampleUserPrincipalFactory();
services.AddSingleton<IUserStore<IdentityUser>, UserStore<IdentityUser>>();
services.AddSingleton<IRoleStore<IdentityRole>>(roleStore);
services.AddSingleton<IUserClaimsPrincipalFactory<IdentityUser>>(userPrincipalFactory);
services.AddIdentity<IdentityUser, IdentityRole>(options =>
{
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@";
}).AddDefaultTokenProviders();
services.AddMvc();
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
I have used AllowedUsernamesCharacters but it makes no difference. I few other old example for similar message advised to define the validator in the AccountsController Constructor but with latest aspnetcore the UserManager no longer has UserValidator property
UserManager.UserValidator = new UserValidator<ApplicationUser>(UserManager) { AllowOnlyAlphanumericUserNames = false };
I doubt My custom implemenation of IdentityUser, Usertore may have some errors, So I will give you those files here
IdentityUser
public class IdentityUser
{
public IdentityUser()
{
Id = Guid.NewGuid().ToString();
}
public IdentityUser(string userName)
: this()
{
UserName = userName;
}
public string Id { get; set; }
public string UserName { get; set; }
public virtual string Email { get; set; }
public virtual bool EmailConfirmed { get; set; }
public virtual string PasswordHash { get; set; }
public virtual string SecurityStamp { get; set; }
public virtual string PhoneNumber { get; set; }
public virtual bool PhoneNumberConfirmed { get; set; }
public virtual bool TwoFactorEnabled { get; set; }
public virtual DateTime? LockoutEndDateUtc { get; set; }
public virtual bool LockoutEnabled { get; set; }
public virtual int AccessFailedCount { get; set; }
}
UserStore
public class UserStore<TUser> : IUserStore<TUser>,
IUserPasswordStore<TUser>,
IUserLoginStore<TUser>,
IUserPhoneNumberStore<TUser>,
IUserTwoFactorStore<TUser>
where TUser : IdentityUser
{
// Workaround create a new userTable instance when ever it is null
private UserTable<TUser> userTable
{
get
{
return new UserTable<TUser>(Database);
}
set
{
}
}
// Workaround create a new Database instance when ever it is null
public MsSqlDatabase Database
{
get
{
return new MsSqlDatabase();
}
private set
{
}
}
public IQueryable<TUser> Users
{
get
{
throw new NotImplementedException();
}
}
public UserStore()
{
new UserStore<TUser>(new MsSqlDatabase());
}
public UserStore(MsSqlDatabase database)
{
Database = database;
userTable = new UserTable<TUser>(database);
//roleTable = new RoleTable(database);
//userRolesTable = new UserRolesTable(database);
//userClaimsTable = new UserClaimsTable(database);
//userLoginsTable = new UserLoginsTable(database);
}
public Task<IdentityResult> CreateAsync(TUser user, CancellationToken cancellationToken)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
userTable.Insert(user);
var a = IdentityResult.Success;
return new Task<IdentityResult>(() => a);
}
public async Task<string> GetUserIdAsync(TUser user, CancellationToken cancellationToken)
{
List<TUser> result = userTable.GetUserById(user.Id) as List<TUser>;
if (result != null && result.Count == 1)
{
return result[0].Id;
}
return null;
}
public async Task<string> GetUserNameAsync(TUser user, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(user.UserName))
{
throw new ArgumentException("Null or empty argument: userName");
}
List<TUser> result = userTable.GetUserByName(user.UserName) as List<TUser>;
// Should I throw if > 1 user?
if (result != null && result.Count == 1)
{
return result[0].UserName;
}
return null;
}
Task<TUser> IUserStore<TUser>.FindByNameAsync(string userName, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(userName))
{
throw new ArgumentException("Null or empty argument: userName");
}
List<TUser> result = userTable.GetUserByName(userName) as List<TUser>;
// Should I throw if > 1 user?
if (result != null && result.Count == 1)
{
return Task.FromResult<TUser>(result[0]);
}
return Task.FromResult<TUser>(null);
}
public Task SetPasswordHashAsync(TUser user, string passwordHash, CancellationToken cancellationToken)
{
user.PasswordHash = passwordHash;
return Task.FromResult<Object>(null);
}
public void Dispose()
{
if (Database != null)
{
Database.Dispose();
Database = null;
}
}
public Task AddLoginAsync(TUser user, UserLoginInfo login, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IdentityResult> DeleteAsync(TUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IList<UserLoginInfo>> GetLoginsAsync(TUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetNormalizedUserNameAsync(TUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetPasswordHashAsync(TUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetPhoneNumberAsync(TUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<bool> GetPhoneNumberConfirmedAsync(TUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<bool> GetTwoFactorEnabledAsync(TUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<bool> HasPasswordAsync(TUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task RemoveLoginAsync(TUser user, string loginProvider, string providerKey, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetNormalizedUserNameAsync(TUser user, string normalizedName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetPhoneNumberAsync(TUser user, string phoneNumber, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetPhoneNumberConfirmedAsync(TUser user, bool confirmed, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetTwoFactorEnabledAsync(TUser user, bool enabled, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetUserNameAsync(TUser user, string userName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IdentityResult> UpdateAsync(TUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
Task<TUser> IUserStore<TUser>.FindByIdAsync(string userId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
Task<TUser> IUserLoginStore<TUser>.FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
**UserTable**
public class UserTable<TUser> where TUser:IdentityUser
{
private MsSqlDatabase _database;
public UserTable(MsSqlDatabase database)
{
_database = database;
}
public string GetUserName(string userId)
{
string commandText = "Select Name from Users where Id = @id";
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
return _database.GetStrValue(commandText, parameters);
}
public string GetUserId(string userName)
{
string commandText = "Select Id from Users where UserName = @name";
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@name", userName } };
return _database.GetStrValue(commandText, parameters);
}
public TUser GetUserById(string userId)
{
TUser user = null;
string commandText = "Select * from Users where Id = @id";
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
var rows = _database.Query(commandText, parameters);
if (rows != null && rows.Count == 1)
{
var row = rows[0];
user = (TUser)Activator.CreateInstance(typeof(TUser));
user.Id = row["Id"];
user.UserName = row["UserName"];
user.PasswordHash = string.IsNullOrEmpty(row["PasswordHash"]) ? null : row["PasswordHash"];
user.SecurityStamp = string.IsNullOrEmpty(row["SecurityStamp"]) ? null : row["SecurityStamp"];
user.Email = string.IsNullOrEmpty(row["Email"]) ? null : row["Email"];
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true : false;
user.PhoneNumber = string.IsNullOrEmpty(row["PhoneNumber"]) ? null : row["PhoneNumber"];
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
user.LockoutEndDateUtc = string.IsNullOrEmpty(row["LockoutEndDateUtc"]) ? DateTime.Now : DateTime.Parse(row["LockoutEndDateUtc"]);
user.AccessFailedCount = string.IsNullOrEmpty(row["AccessFailedCount"]) ? 0 : int.Parse(row["AccessFailedCount"]);
}
return user;
}
public List<TUser> GetUserByName(string userName)
{
List<TUser> users = new List<TUser>();
string commandText = "Select * from Users where UserName = @name";
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@name", userName } };
var rows = _database.Query(commandText, parameters);
foreach (var row in rows)
{
TUser user = (TUser)Activator.CreateInstance(typeof(TUser));
user.Id = row["Id"];
user.UserName = row["UserName"];
user.PasswordHash = string.IsNullOrEmpty(row["PasswordHash"]) ? null : row["PasswordHash"];
user.SecurityStamp = string.IsNullOrEmpty(row["SecurityStamp"]) ? null : row["SecurityStamp"];
user.Email = string.IsNullOrEmpty(row["Email"]) ? null : row["Email"];
user.EmailConfirmed = row["EmailConfirmed"] == "1" ? true : false;
user.PhoneNumber = string.IsNullOrEmpty(row["PhoneNumber"]) ? null : row["PhoneNumber"];
user.PhoneNumberConfirmed = row["PhoneNumberConfirmed"] == "1" ? true : false;
user.LockoutEnabled = row["LockoutEnabled"] == "1" ? true : false;
user.TwoFactorEnabled = row["TwoFactorEnabled"] == "1" ? true : false;
user.LockoutEndDateUtc = string.IsNullOrEmpty(row["LockoutEndDateUtc"]) ? DateTime.Now : DateTime.Parse(row["LockoutEndDateUtc"]);
user.AccessFailedCount = string.IsNullOrEmpty(row["AccessFailedCount"]) ? 0 : int.Parse(row["AccessFailedCount"]);
users.Add(user);
}
return users;
}
public List<TUser> GetUserByEmail(string email)
{
return null;
}
public string GetPasswordHash(string userId)
{
string commandText = "Select PasswordHash from Users where Id = @id";
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@id", userId);
var passHash = _database.GetStrValue(commandText, parameters);
if (string.IsNullOrEmpty(passHash))
{
return null;
}
return passHash;
}
public int SetPasswordHash(string userId, string passwordHash)
{
string commandText = "Update Users set PasswordHash = @pwdHash where Id = @id";
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@pwdHash", passwordHash);
parameters.Add("@id", userId);
return _database.Execute(commandText, parameters);
}
public string GetSecurityStamp(string userId)
{
string commandText = "Select SecurityStamp from Users where Id = @id";
Dictionary<string, object> parameters = new Dictionary<string, object>() { { "@id", userId } };
var result = _database.GetStrValue(commandText, parameters);
return result;
}
public int Insert(TUser user)
{
string commandText = @"Insert into Users (UserName, Id, PasswordHash, SecurityStamp,Email,EmailConfirmed,PhoneNumber,PhoneNumberConfirmed, AccessFailedCount,LockoutEnabled,LockoutEndDateUtc,TwoFactorEnabled)
values (@name, @id, @pwdHash, @SecStamp,@email,@emailconfirmed,@phonenumber,@phonenumberconfirmed,@accesscount,@lockoutenabled,@lockoutenddate,@twofactorenabled)";
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@name", user.UserName);
parameters.Add("@id", user.Id);
parameters.Add("@pwdHash", user.PasswordHash);
parameters.Add("@SecStamp", user.SecurityStamp);
parameters.Add("@email", user.Email);
parameters.Add("@emailconfirmed", user.EmailConfirmed);
parameters.Add("@phonenumber", user.PhoneNumber);
parameters.Add("@phonenumberconfirmed", user.PhoneNumberConfirmed);
parameters.Add("@accesscount", user.AccessFailedCount);
parameters.Add("@lockoutenabled", user.LockoutEnabled);
parameters.Add("@lockoutenddate", user.LockoutEndDateUtc);
parameters.Add("@twofactorenabled", user.TwoFactorEnabled);
return _database.Execute(commandText, parameters);
}
private int Delete(string userId)
{
string commandText = "Delete from Users where Id = @userId";
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@userId", userId);
return _database.Execute(commandText, parameters);
}
public int Delete(TUser user)
{
return Delete(user.Id);
}
public int Update(TUser user)
{
string commandText = @"Update Users set UserName = @userName, PasswordHash = @pswHash, SecurityStamp = @secStamp,
Email=@email, EmailConfirmed=@emailconfirmed, PhoneNumber=@phonenumber, PhoneNumberConfirmed=@phonenumberconfirmed,
AccessFailedCount=@accesscount, LockoutEnabled=@lockoutenabled, LockoutEndDateUtc=@lockoutenddate, TwoFactorEnabled=@twofactorenabled
WHERE Id = @userId";
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("@userName", user.UserName);
parameters.Add("@pswHash", user.PasswordHash);
parameters.Add("@secStamp", user.SecurityStamp);
parameters.Add("@userId", user.Id);
parameters.Add("@email", user.Email);
parameters.Add("@emailconfirmed", user.EmailConfirmed);
parameters.Add("@phonenumber", user.PhoneNumber);
parameters.Add("@phonenumberconfirmed", user.PhoneNumberConfirmed);
parameters.Add("@accesscount", user.AccessFailedCount);
parameters.Add("@lockoutenabled", user.LockoutEnabled);
parameters.Add("@lockoutenddate", user.LockoutEndDateUtc);
parameters.Add("@twofactorenabled", user.TwoFactorEnabled);
return _database.Execute(commandText, parameters);
}
}
MySqlDatabase
public class MsSqlDatabase : IDisposable
{
private SqlConnection _connection;
public MsSqlDatabase()
: this("DefaultConnection")
{
}
public MsSqlDatabase(string connectionStringName)
{
string connectionString = "Server=(localdb)\\mssqllocaldb;Database=SampleIdentity;Trusted_Connection=True;MultipleActiveResultSets=true";
_connection = new SqlConnection(connectionString);
}
public int Execute(string commandText, Dictionary<string, object> parameters)
{
int result = 0;
if (String.IsNullOrEmpty(commandText))
{
throw new ArgumentException("Command text cannot be null or empty.");
}
try
{
EnsureConnectionOpen();
var command = CreateCommand(commandText, parameters);
result = command.ExecuteNonQuery();
}
finally
{
_connection.Close();
}
return result;
}
public object QueryValue(string commandText, Dictionary<string, object> parameters)
{
object result = null;
if (String.IsNullOrEmpty(commandText))
{
throw new ArgumentException("Command text cannot be null or empty.");
}
try
{
EnsureConnectionOpen();
var command = CreateCommand(commandText, parameters);
result = command.ExecuteScalar();
}
finally
{
EnsureConnectionClosed();
}
return result;
}
public List<Dictionary<string, string>> Query(string commandText, Dictionary<string, object> parameters)
{
List<Dictionary<string, string>> rows = null;
if (String.IsNullOrEmpty(commandText))
{
throw new ArgumentException("Command text cannot be null or empty.");
}
try
{
EnsureConnectionOpen();
var command = CreateCommand(commandText, parameters);
using (DbDataReader reader = command.ExecuteReader())
{
rows = new List<Dictionary<string, string>>();
while (reader.Read())
{
var row = new Dictionary<string, string>();
for (var i = 0; i < reader.FieldCount; i++)
{
var columnName = reader.GetName(i);
var columnValue = reader.IsDBNull(i) ? null : reader.GetString(i);
row.Add(columnName, columnValue);
}
rows.Add(row);
}
}
}
finally
{
EnsureConnectionClosed();
}
return rows;
}
private void EnsureConnectionOpen()
{
var retries = 3;
if (_connection.State == ConnectionState.Open)
{
return;
}
else
{
while (retries >= 0 && _connection.State != ConnectionState.Open)
{
_connection.Open();
retries--;
Task.Delay(30).Wait();
}
}
}
public void EnsureConnectionClosed()
{
if (_connection.State == ConnectionState.Open)
{
_connection.Close();
}
}
private DbCommand CreateCommand(string commandText, Dictionary<string, object> parameters)
{
DbCommand command = _connection.CreateCommand();
command.CommandText = commandText;
AddParameters(command, parameters);
return command;
}
private static void AddParameters(DbCommand command, Dictionary<string, object> parameters)
{
if (parameters == null)
{
return;
}
foreach (var param in parameters)
{
var parameter = command.CreateParameter();
parameter.ParameterName = param.Key;
parameter.Value = param.Value ?? DBNull.Value;
command.Parameters.Add(parameter);
}
}
public string GetStrValue(string commandText, Dictionary<string, object> parameters)
{
string value = QueryValue(commandText, parameters) as string;
return value;
}
public void Dispose()
{
if (_connection != null)
{
_connection.Dispose();
_connection = null;
}
}
}
ExampleUserPrincipalFactory
public class ExampleUserPrincipalFactory:IUserClaimsPrincipalFactory<IdentityUser>
{
public Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
{
ClaimsIdentity identity = new ClaimsIdentity("Microsoft.AspNet.Identity.Application");
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
ClaimsPrincipal principal = new ClaimsPrincipal(identity);
return Task.FromResult(principal);
}
}
If you like to see any other class definition please let me know.
Upvotes: 2
Views: 5399
Reputation: 1
I had a similar situation, you have to override the default username in IdentityUser in the model class.
public override UserName {get; set;}
Upvotes: 0
Reputation: 463
My mistake, the UserStore.GetUserNameAsync should fetch the Username from the (Parameter)User object but I was trying to fetch it from the database and it becomes null at that instance, hence username was always blank and the validation failed
Upvotes: 1