Base solution for your next web application
Ends in:
01 DAYS
01 HRS
01 MIN
01 SEC
Open Closed

Set subdomain for HOST tenant #5482


User avatar
0
michelmk2 created

Hi,

I'm trying to use the subdomain as Tenant approach. I updated my appconfig to use the https://{TENANCY_NAME}.clientname.com/. This works fine, how ever.. my host tenant (so the login without a tenant name) is not clientname.com but instead it is admin.clientname.com.

This causes some errors though. If I navigate to admin.clientname.com and log in. I am actually in the host environment. When I then login as a tenant through the Tenant menu, it all works fine. How ever, when I try to switch back to the host, I recieve the following error: "Current tenant is different than given tenant. AbpSession.TenantId: 19, given TenantId: ".

The above is probably because it expects the host domain to be clientname.com, but instead it is host.clientname.com.

Is there any way to set the host subdomain somewhere, or fix this some other way?

EDIT: Using version v5.2.6 ASPNET CORE MVC & JQUERY .NET Framework

Thanks in advance!


14 Answer(s)
  • User Avatar
    0
    aaron created
    Support Team

    Fixed in v5.6

  • User Avatar
    0
    michelmk2 created

    <cite>aaron: </cite> Fixed in v5.6

    Hmmm, still doesn't work... getting the following error when switching back to host:

    System.Exception: Current tenant is different than given tenant. AbpSession.TenantId: 18, given tenantId: 
       at Robin.Authorization.Impersonation.ImpersonationManager.CheckCurrentTenant(Nullable`1 tenantId)
       at Robin.Authorization.Impersonation.ImpersonationManager.&lt;GetImpersonatedUserAndIdentity&gt;d__8.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Robin.Web.Controllers.AccountController.&lt;ImpersonateSignIn&gt;d__51.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Abp.Threading.InternalAsyncHelper.&lt;AwaitTaskWithPostActionAndFinallyAndGetResult&gt;d__5`1.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at lambda_method(Closure , Object )
       at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
       at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.TaskOfActionResultExecutor.<Execute>d__0.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__12.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runti...
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @michelmk2,

    You need to implement your own DomainTenantResolveContributor and return null if found tenancy name is admin. See <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/src/Abp.AspNetCore/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs">https://github.com/aspnetboilerplate/as ... ributor.cs</a>

  • User Avatar
    0
    michelmk2 created

    <cite>ismcagdas: </cite> Hi @michelmk2,

    You need to implement your own DomainTenantResolveContributor and return null if found tenancy name is admin. See <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/src/Abp.AspNetCore/AspNetCore/MultiTenancy/DomainTenantResolveContributor.cs">https://github.com/aspnetboilerplate/as ... ributor.cs</a>

    Thanks for your reply! Do you have an example on how to implement this? Because i'm not sure how and where to put it!

    Thank you so much!

  • User Avatar
    0
    ismcagdas created
    Support Team

    It should be something like this;

    public class MyDomainTenantResolveContributor : ITenantResolveContributor, ITransientDependency 
    {
    	public int? ResolveTenantId()
    	{
    		if (_multiTenancyConfiguration.DomainFormat.IsNullOrEmpty())
    		{
    			return null;
    		}
    
    		var httpContext = _httpContextAccessor.HttpContext;
    		if (httpContext == null)
    		{
    			return null;
    		}
    		 
    		var hostName = httpContext.Request.Host.Host.RemovePreFix("http://", "https://").RemovePostFix("/");
    		var domainFormat = _multiTenancyConfiguration.DomainFormat.RemovePreFix("http://", "https://").Split(':')[0].RemovePostFix("/");
    		var result = new FormattedStringValueExtracter().Extract(hostName, domainFormat, true, '/');
    
    		if (!result.IsMatch || !result.Matches.Any())
    		{
    			return null;
    		}
    
    		var tenancyName = result.Matches[0].Value;
    		if (tenancyName.IsNullOrEmpty())
    		{
    			return null;
    		}
    
    		if(tenancyName == "admin"){ // this is the added line
    			return null;
    		}
    		
    		if (string.Equals(tenancyName, "www", StringComparison.OrdinalIgnoreCase))
    		{
    			return null;
    		}
    
    		var tenantInfo = _tenantStore.Find(tenancyName);
    		if (tenantInfo == null)
    		{
    			return null;
    		}
    
    		return tenantInfo.Id;	
    	}
    }
    

    Then, add it to resolvers in the PreInitalize method of your web module

    Configuration.MultiTenancy.Resolvers.Insert(0,new MyDomainTenantResolveContributor());
    
  • User Avatar
    0
    michelmk2 created

    <cite>ismcagdas: </cite> It should be something like this;

    public class MyDomainTenantResolveContributor : ITenantResolveContributor, ITransientDependency 
    {
      public int? ResolveTenantId()
      {
      	if (_multiTenancyConfiguration.DomainFormat.IsNullOrEmpty())
      	{
      		return null;
      	}
    
      	var httpContext = _httpContextAccessor.HttpContext;
      	if (httpContext == null)
      	{
      		return null;
      	}
      	 
      	var hostName = httpContext.Request.Host.Host.RemovePreFix("http://", "https://").RemovePostFix("/");
      	var domainFormat = _multiTenancyConfiguration.DomainFormat.RemovePreFix("http://", "https://").Split(':')[0].RemovePostFix("/");
      	var result = new FormattedStringValueExtracter().Extract(hostName, domainFormat, true, '/');
    
      	if (!result.IsMatch || !result.Matches.Any())
      	{
      		return null;
      	}
    
      	var tenancyName = result.Matches[0].Value;
      	if (tenancyName.IsNullOrEmpty())
      	{
      		return null;
      	}
    
      	if(tenancyName == "admin"){ // this is the added line
      		return null;
      	}
      	
      	if (string.Equals(tenancyName, "www", StringComparison.OrdinalIgnoreCase))
      	{
      		return null;
      	}
    
      	var tenantInfo = _tenantStore.Find(tenancyName);
      	if (tenantInfo == null)
      	{
      		return null;
      	}
    
      	return tenantInfo.Id;	
      }
    }
    

    Then, add it to resolvers in the PreInitalize method of your web module

    Configuration.MultiTenancy.Resolvers.Insert(0,new MyDomainTenantResolveContributor());
    

    Still doesn't work unfortunately. Getting the following error:

    System.ArgumentNullException: Value cannot be null.
    Parameter name: value
       at System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue)
       at System.Security.Claims.Claim..ctor(String type, String value)
       at Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory`1.&lt;GenerateClaimsAsync&gt;d__10.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory`2.<GenerateClaimsAsync>d__5.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory`1.&lt;CreateAsync&gt;d__9.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Abp.Authorization.AbpUserClaimsPrincipalFactory`2.<CreateAsync>d__1.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Abp.Threading.InternalAsyncHelper.<AwaitTaskWithPostActionAndFinallyAndGetResult>d__5`1.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwa...
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    @michelmk2 does it work like it used to be when you comment out the line below ?

    Configuration.MultiTenancy.Resolvers.Insert(0,new MyDomainTenantResolveContributor());
    
  • User Avatar
    0
    michelmk2 created

    <cite>ismcagdas: </cite> @michelmk2 does it work like it used to be when you comment out the line below ?

    Configuration.MultiTenancy.Resolvers.Insert(0,new MyDomainTenantResolveContributor());
    

    That gives me the same error as above :(.

  • User Avatar
    0
    ismcagdas created
    Support Team

    @michelmk2 sorry for our late response. This is strange. If you comment out the code I have suggested, it should take you back to old case.

    Did you make additional changes on the project regarding to this problem ?

  • User Avatar
    0
    michelmk2 created

    <cite>ismcagdas: </cite> @michelmk2 sorry for our late response. This is strange. If you comment out the code I have suggested, it should take you back to old case.

    Did you make additional changes on the project regarding to this problem ?

    Unfortunately I'm still having the same problem. Tried all kinds of things.

    I just discovered that the error I'm getting is because in the UserLinkManager.cs, method GetSwitchedUserAndIdentity, the _userManager is null, therefore it crashes and I get the error the the value cannot be null. The _userManager in the UserLinkManager class is not empty when I switch between tenants (subdomainds) it ONLY happens when I switch back to the host. :(.

    Any idea why it's empty when switch back to the host? Thanks!!

  • User Avatar
    0
    ismcagdas created
    Support Team

    @michelmk2 this is strange. UserLinkManager class is craeted via dependency injection, so UserManager on it also created via DI.

    I couldn't understand why UserManager is null when switching back to host.

    If this is a repeatable problem on your project, could you share your project via email ?

  • User Avatar
    0
    michelmk2 created

    <cite>ismcagdas: </cite> @michelmk2 this is strange. UserLinkManager class is craeted via dependency injection, so UserManager on it also created via DI.

    I couldn't understand why UserManager is null when switching back to host.

    If this is a repeatable problem on your project, could you share your project via email ?

    Thanks, I will somewhere next week!

  • User Avatar
    0
    michelmk2 created

    I still have this issue. I just sent you a sample project again in which you can see what goes wrong. The email is from [email protected].

    Thanks,

    Bart

  • User Avatar
    0
    michelmk2 created

    Fixed by applying https://github.com/aspnetzero/aspnet-zero-core/issues/1609!