Base solution for your next web application
Open Closed

How to use AbpSession in the Global.asax #1897


User avatar
0
amrsaafan created

Hello,

How to use AbpSession in the Global.asax in another words I want to set the current tenant ID based on the subdomain segment and I do that in Application_BeginRequest but I faced a problem that how to set tenant ID of the current AbpSession.

This could be for unauthenticated requests.


1 Answer(s)
  • User Avatar
    0
    jefftindall created

    If the goal is to filter database requests based on the subdomain, then you can use an interceptor on the application services to set the tenant ID on the unit of work.

    public class SubdomainTenantInterceptor : IInterceptor
        {
            private readonly IUnitOfWorkManager _unitOfWorkManager;
    
            public SubdomainTenantInterceptor(IUnitOfWorkManager unitOfWorkManager)
            {
                _unitOfWorkManager = unitOfWorkManager;
            }
    
            public void Intercept(IInvocation invocation)
            {
                if (_unitOfWorkManager.Current != null)
                {
                    if (HttpContext.Current.Request.Url.HostNameType == UriHostNameType.Dns)
                    {
                        var cacheManager = IocManager.Instance.Resolve<ICacheManager>();
                        var tenantCache = cacheManager.GetCache<string, Tenant>("TenantCache");
    
                        // Try to get tenant name from sub-domain
                        string tenantName = HttpContext.Current.Request.Url.Host.Split('.')[0];
    
                        Tenant t = tenantCache.Get(tenantName,
                            () =>
                            {
                            // attempt to look up
                            return AsyncContext.Run<Tenant>(() => GetTenant(tenantName));
                            });
    
                        if (t != null)
                        {
                            // Set tenant ID
                            _unitOfWorkManager.Current.SetTenantId(t.Id);
                        }
                    }
                }
    
                invocation.Proceed();
            }
    
            private async Task<Tenant> GetTenant(string tenantName)
            {
                TenantManager manager = IocManager.Instance.Resolve<TenantManager>();
                Tenant t = await manager.FindByTenancyNameAsync(tenantName);
                return t;
            }
        }
    

    and register it in the WebModule

    public override void PreInitialize()
            {
                //...
                Configuration.IocManager.IocContainer.Kernel.ComponentRegistered += Kernel_ComponentRegistered;
            }
    
            private void Kernel_ComponentRegistered(string key, Castle.MicroKernel.IHandler handler)
            {
                if (typeof(IApplicationService).IsAssignableFrom(handler.ComponentModel.Implementation))
                {
                    handler.ComponentModel.Interceptors.Add
                    (new InterceptorReference(typeof(SubdomainTenantInterceptor)));
                }
            }
    

    For unauthenticated requests, you may also need this information on the client side. In that case, modify the SessionAppService.

    public async Task<GetCurrentLoginInformationsOutput> GetCurrentLoginInformations()
            {
                var output = new GetCurrentLoginInformationsOutput
                {
                    User = (await GetCurrentUserAsync()).MapTo<UserLoginInfoDto>()
                };
    
                if (AbpSession.TenantId.HasValue)
                {
                    output.Tenant = (await GetCurrentTenantAsync()).MapTo<TenantLoginInfoDto>();
                }
                else
                {
                    int? tenantId = _unitOfWorkManager.Current.GetTenantId();
                    if (tenantId.HasValue)
                    {
                        output.Tenant = (await TenantManager.GetByIdAsync(tenantId.Value)).MapTo<TenantLoginInfoDto>();
                    }
                }
    
                return output;
            }
    

    If using the default header.js, then you'll need to add additional checks to avoid null references.

    vm.getShownUserName = function () {
                    if (!abp.multiTenancy.isEnabled) {
                        return appSession.user.userName;
                    } else {
                        if (appSession.tenant && appSession.user) {
                            return appSession.tenant.tenancyName + '\\' + appSession.user.userName;
                        } else {
                            if (appSession.user)
                                return '.\\' + appSession.user.userName;
                            else
                                return '';
                        }
                    }
                };