Open HDScarpe opened 2 years ago
This is log error
System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method343(Closure , QueryContext )
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, Cancel
lationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, LambdaExpression expression,
CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, Expression`1 predicate, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9.FindByNameAsync(String normalizedUserName, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)
at Microsoft.AspNetCore.Identity.SignInManager`1.PasswordSignInAsync(String userName, String password, Boolean isPersistent, Boolean lockoutOnFailure)
at IdentityProvider.Pages.Login.Index.OnPost() in D:\2022\.NET\eHosSystem\IdentityProvider\src\IdentityProvider\Pages\Account\Login\Index.cshtml.cs:line 96
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Convert[T](Object taskAsObject)
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments)
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_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()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
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 Duende.IdentityServer.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession userSession, IEventService events, IIssuerNameService is
suerNameService, ISessionCoordinationService sessionCoordinationService) in /_/src/IdentityServer/Hosting/IdentityServerMiddleware.cs:line 116
at Duende.IdentityServer.Hosting.MutualTlsEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes) in /_/src/IdentityServer/Hosting/MutualTlsEndpointM
iddleware.cs:line 94
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Duende.IdentityServer.Hosting.DynamicProviders.DynamicSchemeAuthenticationMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/DynamicProviders/DynamicScheme
s/DynamicSchemeAuthenticationMiddleware.cs:line 47
at Duende.IdentityServer.Hosting.BaseUrlMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/BaseUrlMiddleware.cs:line 27
at Finbuckle.MultiTenant.AspNetCore.MultiTenantMiddleware.Invoke(HttpContext context)
at IdentityProvider.Extensions.ErrorWrappingMiddleware.Invoke(HttpContext context) in D:\2022\.NET\eHosSystem\IdentityProvider\src\IdentityProvider\Extensions\ErrorWrappingMiddlew
are.cs:line 23
I'm experiencing the same problem, albeit with a different setup. The initial problem is a duplicate index:
InvalidOperationException: The indexes {'NormalizedUserName', 'TenantId'} on 'ApplicationUser' and {'NormalizedUserName'} on 'ApplicationUser' are both mapped to 'AspNetUsers.UserNameIndex', but with different columns ({'NormalizedUserName', 'TenantId'} and {'NormalizedUserName'}).
This can be addressed by adding some config in the DbContext's OnModelCreating override:
modelBuilder.Entity<ApplicationUser>()
.Metadata
.RemoveIndex(new[] { modelBuilder.Entity<ApplicationUser>().Property(u => u.NormalizedUserName).Metadata });
But that's where the above error message pops up. Specifically, in the ApplicationUserStore
that's a child of UserStore<ApplicationUser>
. Any time I want to invoke the Users
property, the error as described here occurs.
My multi-tenancy setup is pretty simple:
services
.AddMultiTenant<TenantInfo>()
.WithClaimStrategy()
.WithConfigurationStore();
There are some docs on the subject, but I can't fathom what should be done to solve this.
@HDScarpe do you think you can recreate the issue in a test project with just ASP.NET Core Identity and taking IdentityServer out of the picture for a moment? Also can you tell me more about your IdentityContext
and maybe post the class?
Looking at code where the exception is, looks like its in the UserManager.GetByNameAsyc
which is this code:
which boils down to:
Users.FirstOrDefaultAsync(u => u.NormalizedUserName == normalizedUserName, cancellationToken);
on the underlying db context. Just as a test, if you manually instantiate your dbcontext with a tenant and try the line above do you get the same error?
@hbulens do you mind posting your dbcontext class or providing a repo that shows the error in action?
Will try to provide an isolated case when I can get to it.
public class MyDbContext : MultiTenantIdentityDbContext<ApplicationUser>
{
public MyDbContext (ITenantInfo tenantInfo, DbContextOptions options)
: base(tenantInfo, options)
{
TenantNotSetMode = TenantNotSetMode.Overwrite;
}
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
// Breaking change in EF Core 7.0 to allow triggers
configurationBuilder.Conventions.Add(_ => new BlankTriggerAddingConvention());
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Ignore<IdentityUserClaim<string>>();
modelBuilder.Ignore<IdentityUserRole<string>>();
modelBuilder.Ignore<IdentityUserLogin<string>>();
modelBuilder.Ignore<IdentityRoleClaim<string>>();
modelBuilder.Ignore<IdentityUserToken<string>>();
modelBuilder.ApplyConfiguration(new CalendarMap());
// ... ommitted the other configs
}
}
Seems like we've been able to create a workaround by overriding UserClaimsPrincipalFactory.GenerateClaimsAsync and commenting out the following lines:
//if (UserManager.SupportsUserClaim)
//{
// id.AddClaims(await UserManager.GetClaimsAsync(user).ConfigureAwait(false));
//}
That seems to work but it's a rather ugly solution, so we'll need to look into this a bit further.
@hbulens Did you manage to fix this? I have a very similar error:
Currently I am setting up Finbuckle.MultiTenant with Duende IdentityServer. I'm getting an error when I log into the root account If I don't use .IsMultiTenant() then it can login as root account but can't login tenant account. This is my class design
I have 3 classes: IdentityContext , BaseDbContext , TenantDbContext
IdentityContext : BaseDbContext
BaseDbContext : MultiTenantIdentityDbContext<User, IdentityRole, string, IdentityUserClaim<string>, IdentityUserRole<string>, IdentityUserLogin<string>, IdentityRoleClaim<string>, IdentityUserToken<string>>
TenantDbContext : EFCoreStoreDbContext<ScarpeTenant>
And this is AddMultiTenant