nhibernate / nhibernate.aspnetcore.identity Goto Github PK
View Code? Open in Web Editor NEWASP.NET Core Identity Provider for NHibernate
License: GNU Lesser General Public License v2.1
ASP.NET Core Identity Provider for NHibernate
License: GNU Lesser General Public License v2.1
Hi, I'm getting this exception when I try to add a new IdentityUser
with the default mapping:
PostgresException: 23502: null value in column "id" violates not-null constraint
Npgsql.NpgsqlConnector+<>c__DisplayClass160_0+<g__ReadMessageLong|0>d.MoveNext()
GenericADOException: could not insert: [NHibernate.AspNetCore.Identity.IdentityUser][SQL: INSERT INTO public.aspnet_users (user_name, normalized_user_name, email, normalized_email, email_confirmed, phone_number, phone_number_confirmed, lockout_enabled, lockout_end_unix_time_milliseconds, password_hash, security_stamp, concurrency_stamp, two_factor_enabled, access_failed_count) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) returning id]
NHibernate.Id.Insert.AbstractReturningDelegate.PerformInsertAsync(SqlCommandInfo insertSQL, ISessionImplementor session, IBinder binder, CancellationToken cancellationToken)
Am I doing something wrong?
At the moment types like NHibernate.AspNetCore.Identity.IdentityRole
cannot have an id column other than string. It would be great if we could choose this type for ourselves.
When property variable is "NHibernate.Dialect.MsSql2012Dialect, NHibernate, Version=5.3.0.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4" the code incorrectly runs cfg.AddIdentityMappingsForPostgres();
Seems as though the condition on the if statement should be > -1 and not >= -1 since -1 means not a match.
I am having some issues getting this up and running. I am using Fluent Hiberate to do my class mappings and I am unable to create a user table that lets me create a user. In my Startup.cs I have something that looks like this
services.AddSingleton(_ =>
{
var config = new Configuration().AddIdentityMappingsForSqlServer();
return Fluently.Configure(config)
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(
Configuration.GetConnectionString("MyDbConnection")))
.Mappings(m => { m.FluentMappings.AddFromAssemblyOf<Startup>(); })
.ExposeConfiguration(cfg =>
{
#if DEBUG
new SchemaUpdate(cfg).Execute(false, true);
#endif
})
.BuildConfiguration();
});
services.AddSingleton(sp => sp.GetRequiredService<Configuration>().BuildSessionFactory());
services.AddScoped(provider => provider.GetService<ISessionFactory>().OpenSession());
and I have created an AppUser.cs like so
using System.Collections.Generic;
using NHibernate.AspNetCore.Identity;
namespace Api.Domain
{
// Add profile data for application users by adding properties to the AppUser class
public class AppUser : IdentityUser
{
// Properties to come late
}
}
and a corresponding Map file
using Api.Domain;
using FluentNHibernate.Mapping;
namespace Api.Persistence.NHibernate
{
public class AppUserMap : ClassMap<AppUser>
{
public AppUserMap()
{
Id(x => x.Id)
.GeneratedBy.UuidHex("N");
Map(x => x.AccessFailedCount);
Map(x => x.ConcurrencyStamp).Length(32);
Map(x => x.Email).Length(256);
Map(x => x.NormalizedEmail).Length(256);
Map(x => x.EmailConfirmed).Not.Nullable();
Map(x => x.LockoutEnabled).Not.Nullable();
Map(x => x.LockoutEnd);
Map(x => x.PasswordHash).Length(256);
Map(x => x.PhoneNumber).Length(128);
Map(x => x.PhoneNumberConfirmed).Not.Nullable();
Map(x => x.TwoFactorEnabled).Not.Nullable();
Map(x => x.UserName)
.Length(64)
.Unique()
.Not.Nullable();
Map(x => x.NormalizedUserName)
.Length(64)
.Not.Nullable()
.Unique();
Map(x => x.SecurityStamp)
.Length(64);
Table("AspNetUsers");
}
}
}
which has come from here. When I attempt to use the UserManager to create a user I get the following in my debug log
dbug: NHibernate.SQL[0]
Batch commands:
command 0:INSERT INTO AspNetUsers (AccessFailedCount, ConcurrencyStamp, Email, NormalizedEmail, EmailConfirmed, LockoutEnabled, LockoutEnd, PasswordHash, PhoneNumber, PhoneNumberConfirmed, TwoFactorEnabled, UserName, NormalizedUserName, SecurityStamp, Id) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14);@p0 = 0 [Type: Int32 (0:0:0)], @p1 = '32de7879-d609-4a78-82ee-37650e454f5b' [Type: String (36:0:0)], @p2 = NULL [Type: String (4000:0:0)], @p3 = NULL [Type: String (4000:0:0)], @p4 = False [Type: Boolean (0:0:0)], @p5 = True [Type: Boolean (0:0:0)], @p6 = NULL [Type: DateTimeOffset (10:0:0)], @p7 = NULL [Type: String (4000:0:0)], @p8 = NULL [Type: String (4000:0:0)], @p9 = False [Type: Boolean (0:0:0)], @p10 = False [Type: Boolean (0:0:0)], @p11 = '754f8e5a7baf4e9fad97d2042ae63ad8' [Type: String (64:0:0)], @p12 = '754F8E5A7BAF4E9FAD97D2042AE63AD8' [Type: String (64:0:0)], @p13 = 'IMC5PYQMAD2NFKYPBG5DDE3O3V3BFBQ4' [Type: String (64:0:0)], @p14 = '8610930d5f9b48fcbfed5429c2390358' [Type: String (4000:0:0)]
dbug: NHibernate.Connection.DriverConnectionProvider[0]
Obtaining DbConnection from Driver
dbug: NHibernate.Util.ADOExceptionReporter[0]
could not execute batch command.
[ SQL not available ]
System.Data.SqlClient.SqlException (0x80131904): String or binary data would be truncated.
The statement has been terminated.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader()
at System.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult)
at System.Data.SqlClient.SqlCommand.EndExecuteNonQuery(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at NHibernate.AdoNet.GenericBatchingBatcher.BatchingCommandSet.ExecuteNonQueryAsync(CancellationToken cancellationToken)
at NHibernate.AdoNet.GenericBatchingBatcher.DoExecuteBatchAsync(DbCommand ps, CancellationToken cancellationToken)
ClientConnectionId:e9f4ee77-797a-4e80-8a36-2c46af4ca461
Error Number:8152,State:13,Class:16
System.Data.SqlClient.SqlException (0x80131904): String or binary data would be truncated.
The statement has been terminated.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader()
at System.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult)
at System.Data.SqlClient.SqlCommand.EndExecuteNonQuery(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at NHibernate.AdoNet.GenericBatchingBatcher.BatchingCommandSet.ExecuteNonQueryAsync(CancellationToken cancellationToken)
at NHibernate.AdoNet.GenericBatchingBatcher.DoExecuteBatchAsync(DbCommand ps, CancellationToken cancellationToken)
ClientConnectionId:e9f4ee77-797a-4e80-8a36-2c46af4ca461
What can I do to fix this? Also is there a better way of adding the mappings for my AppUser?
The mapping of IdentityRole
, IdentityUser
related entity is xml mapping, The only way to extend these mapping is using subclass mapping like JoinedSubclassMapping
, but exit mappings of these classes can not be modified.
Refact these mappings to use NHibernate.Mapping.ByCode
, allow users to modify these mapping through inheritance。
I got the following error when a new user is created the second time:
System.AggregateException: One or more errors occurred. (Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
at NHibernate.Impl.SessionImpl.FlushAsync(CancellationToken cancellationToken)
at NHibernate.AspNetCore.Identity.UserStore`2.FlushChangesAsync(CancellationToken cancellationToken) in C:\Code\NHibernate.AspNetCore.Identity\src\NHibernate.AspNetCore.Identity\UserStore.cs:line 587
at NHibernate.AspNetCore.Identity.UserStore`2.CreateAsync(TUser user, CancellationToken cancellationToken) in C:\Code\NHibernate.AspNetCore.Identity\src\NHibernate.AspNetCore.Identity\UserStore.cs:line 47
at Microsoft.AspNetCore.Identity.UserManager`1.CreateAsync(TUser user)
at Microsoft.AspNetCore.Identity.UserManager`1.CreateAsync(TUser user, String password)
My implementation as follows:
...
cfg.SetProperty("default_flush_mode", "Commit");
cfg.SetProperty("connection.isolation", "ReadUncommitted");
cfg.SetProperty("adonet.batch_size", "10");
cfg.SetProperty("default_batch_fetch_size", "1");
cfg.SetProperty("generate_statistics", "false");
cfg.SetProperty("show_sql", "false");
cfg.SetProperty("format_sql", "false");
cfg.SetProperty("connection.driver_class", "NHibernate.Driver.SqlClientDriver,NHibernate");
cfg.SetProperty("dialect", "NHibernate.Dialect.MsSql2008Dialect");
...
services.AddSingleton(s => s.GetRequiredService<Configuration>().BuildSessionFactory());
services.AddScoped(s => s.GetRequiredService<ISessionFactory>().WithOptions().Interceptor(new AppInterceptor(s)).OpenSession());
...
services.AddIdentityCore<AppUser>(options => { ... })
.AddRoles<AppRole>()
.AddHibernateStores()
.AddDefaultTokenProviders();
services.AddScoped<IRoleStore<AppRole>>(s => new RoleStore<AppRole>(s.GetRequiredService<ISession>(), new IdentityErrorDescriber()));
...
using (var scope = host.Services.CreateScope())
{
using (var tran = session.BeginTransaction())
{
var appUser1 = new AppUser(name1, email1);
await _userManager.CreateUserAsync(appUser1, roles, password);
var appUser2 = new AppUser(name2, email2);
await _userManager.CreateUserAsync(appUser2, roles, password); // Error is thrown here
tran.Commit();
}
}
As u can see the error is thrown on the second user creation _userManager.CreateUserAsync(appUser2, roles, password)
.
So I assume it is because of the session.Clear()
in UserStore.FlushChangesAsync()
.
Column lockout_end_unix_time_milliseconds
causes an error on Oracle 11g database.
Error:
OracleException (0x80004005): ORA-00972: identifier is too long
The column name must be up to 30 characters.
I would like to be able to derive from the IdentityUser and IdentityRole classes to associate more data with them. (This is possible with the EFCore adapter as well)
Currently, this will result in the IoC container bindings to not resolve properly, because it cannot resolve, for example, IUserStore<IdentityUser>
to UserStore<ApplicationUser>
, even though ApplicationUser
is derived from IdentityUser
.
I can help out with a PR for that if you agree that should be possible.
Add README.md and sample usage.
I am getting this issue when trying to add role to user
I am using fluent mapping as follow, table was successfully created. Also the user and the role is in database already. So they were created successfully.
public class AppUserRoleMap : ClassMapping<AppUserRole>
{
public AppUserRoleMap()
{
Table("AspNetUserRoles");
ComposedId(x =>
{
Property(y => y.UserId, y =>
{
y.Type(NHibernateUtil.String);
y.Length(32);
y.Column("UserId");
});
Property(y => y.RoleId, y =>
{
y.Type(NHibernateUtil.String);
y.Length(32);
y.Column("RoleId");
});
});
}
}
I am using NHibernate.AspNetCore.Identity and I have two custom columns for user like CityId and CountryId. But while using UserManager the custom Columns are not inserted to the database
Mapping:
References(x => x.Country).Column("CountryId");
References(x => x.City).Column("CityId");
identity setting
services.AddDefaultIdentity<AppUser>(opts =>
{
opts.Password.RequireDigit = false;
opts.Password.RequireLowercase = false;
opts.Password.RequireUppercase = true;
opts.Password.RequireNonAlphanumeric = false;
opts.Password.RequiredLength = 7;
})
.AddRoles<AppRole>()
.AddHibernateStores();
AppUser class
public class AppUser : NHIdentityUser
{
public virtual DateTime CreatedDate { get; set; }
public virtual DateTime LastModifiedDate { get; set; }
public virtual string DisplayName { get; set; }
public virtual DateTime? LastLogin { get; set; }
public virtual int LoginCount { get; set; }
public virtual int Token { get; set; }
public virtual int CountryId { get; set; }
public virtual Country Country { get; set; }
public virtual int CityId { get; set; }
public virtual City City { get; set; }
public virtual string DescriptionAboutAddress { get; set; }
public virtual IEnumerable<Direction> Directions { get; set; }
}
using UserManager
private readonly UserManager<AppUser> _userManager;
//...
return await _userManager.CreateAsync(user, password);
Mappings are correct and I have theses columns in DB.
I just wonder about is there any issue related UserManager?
Hi,
can you give an ETA about adding MySQL bindings, please?
Regards.
I am using PostgreSQL db. I generate my own identifiers by using my own IIdentifierGenerator
including IdentityUser and IdentityRole ids. The ids look like 2x72e5rm5r2znp0w
. Everything works perfect except of the method NHibernate.AspNetCore.Identity.UserStore.AddToRoleAsync(TUser user, String normalizedRoleName, CancellationToken cancellationToken)
. It throws an exception: "System.InvalidOperationException: Role 2X72E5RM5R2ZNP0W not found!". Take a note that I am passing lowercase id.
I made a workaround by passing uppercase ID in my UserService but I think it might be a small issue with this library. Please feel free to ask any questions.
Hi, trying to modify webtest so it works on MSSQL but somehow im getting the above exception when i'm trying to register a user.
My hibernate config is this:
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.connection_string">Server=.;database=TEST_Data;Trusted_Connection=SSPI; </property>
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="adonet.batch_size">10</property>
<mapping assembly="WebTest" />
</session-factory>
</hibernate-configuration>
After read the document of ConcurrencyStamp , I think this field should be mapped as version field.
But with Microsoft's default implementation, it is generated as guid string, not the same behavior nhibernate's version.
Any suggestions? @fredericDelaporte @milesibastos @julian-maughan @fabiomaulo @
As ms official provider, implement a user only store, for website which does not need roles.
I integrated SignalR into my app some time after using your ISession injection implementation with Identity.
The problem is that signalr is connected with identity and ISession's injected in the identity implementation stay open.
So each Hub from SignalR Keep in Context identity and injected sessions are never kill.
So one session stay open for each Hub.
I was thinking to inject ISessionFactory in identity and open the sessions in the implemented methods for kills Sessions at each end of action but I do not know if this method is suitable, Knowing that the implementation of Users in UserStore is IQueryable so this would not be very safe to do something like:
private readonly ISessionFactory _sessionFactory;
public override IQueryable<User> Users
{
get
{
using (ISession session = _sessionFactory.OpenSession())
{
return session.Query<User>();
}
}
}
public UserStore(ISessionFactory sessionFactory, IdentityErrorDescriber errorDescriber) : base(errorDescriber)
{
_sessionFactory = sessionFactory;
}
what do you think about this case ?
Thank for your times.
The table names in mapping does not match table names in SQL scripts. I would think the underscores (_) should be removed or?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.