Activities of "liangshiwei"

Hi,

As I understand, a customer is a tenant. a facility can belong to multiple customers.

Just an idea:

The Facility entity should not implement the IMultiTenant interface, so It will be in the host database.

public class Facility: ...
{
    public List<Guid> TenantIds {get; set;}
}

public class TestAppService:....
{
    private readonly IRepository<Facility, Guid> _reopsitory;
    .....    
 
    public async Task GetReportAsync()
    {
        var currentTenantId = CurrentTenant.GetId();
        //Switch to host
        using(CurrentTenant.Change(null))
        {
          var result = await  _reopsitory.GetListAsync(x => x.TenantIds.Contains(currentTenantId));
        }
        
    }
}

is it a way to refresh redis?

I didn't get it.

I tested on my localhost and it works. Also something interesting is, any idea why jquery is not on production ?

The bundle system will bundles & minifies for the production environment: https://docs.abp.io/en/abp/latest/UI/AspNetCore/Bundling-Minification#bundling-mode

You can try configuring the AbpBundlingOptions or ignore Jquery file.

Configure<AbpBundlingOptions>(options =>
{
    options.Mode = BundlingMode.None;
});

Or..

Configure<AbpBundlingOptions>(options =>
{
    options.MinificationIgnoredFiles.Add("/lib/jquery/jquery.js");
});

Hi,

This is a bug, we will fix it in the next patch version, and your ticket refunded.

is it possible to override a bundles, global bundles to make jquery be present first. is it possible to override the main layout.cshtml like vies/pages/_Layout.cshtml to load jquery manually here

Hi,

You can try:

public class MyBundleContributor : BundleContributor
{
    public override void ConfigureBundle(BundleConfigurationContext context)
    {
        context.Files.Insert(0, "/lib/jquery/jquery.js");
    }
}

Configure<AbpBundlingOptions>(options =>
{
    options.ScriptBundles.Configure(
        LeptonXThemeBundles.Scripts.Global,
        bundle =>
        {
            bundle.AddContributors(new MyBundleContributor());
        }
    );
});

: )

https://github.com/abpframework/abp/pull/18264

The count seems to include users that have been soft deleted which we believe is misleading to users.

Yes, that is the problem, we have enhanced this in 8.0: https://github.com/abpframework/abp/pull/18051

I will do the same in 7.4.

You may need to manually delete the records in the table AbpUserRoles.

HI,

Ok, you can try override the OnGetExternalLoginCallbackAsync method


[ExposeServices(typeof(LoginModel))]
public class MyLoginModel : LoginModel
{
    [UnitOfWork]
    public override async Task<IActionResult> OnGetExternalLoginCallbackAsync(string returnUrl = "", string returnUrlHash = "", string remoteError = null)
    {
        if (remoteError != null)
        {
            Logger.LogWarning($"External login callback error: {remoteError}");
            return RedirectToPage("./Login");
        }

        await IdentityOptions.SetAsync();

        var loginInfo = await SignInManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            Logger.LogWarning("External login info is not available");
            return RedirectToPage("./Login");
        }

        IsLinkLogin = await VerifyLinkTokenAsync();

        var result = await SignInManager.ExternalLoginSignInAsync(
            loginInfo.LoginProvider,
            loginInfo.ProviderKey,
            isPersistent: true,
            bypassTwoFactor: true
        );

        if (!result.Succeeded)
        {
            await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
            {
                Identity = IdentitySecurityLogIdentityConsts.IdentityExternal,
                Action = "Login" + result
            });
        }

        if (result.IsLockedOut)
        {
            Logger.LogWarning($"Cannot proceed because user is locked out!");
            return RedirectToPage("./LockedOut", new {
                returnUrl = ReturnUrl,
                returnUrlHash = ReturnUrlHash
            });
        }

        if (result.IsNotAllowed)
        {
            Logger.LogWarning($"External login callback error: User is Not Allowed!");

            var user = await UserManager.FindByLoginAsync(loginInfo.LoginProvider, loginInfo.ProviderKey);
            if (user.IsActive)
            {
                await StoreConfirmUser(user);
                return RedirectToPage("./ConfirmUser", new {
                    returnUrl = ReturnUrl,
                    returnUrlHash = ReturnUrlHash
                });
            }

            return RedirectToPage("./Login");
        }

        if (result.Succeeded)
        {
            var user = await UserManager.FindByLoginAsync(loginInfo.LoginProvider, loginInfo.ProviderKey);
            if (IsLinkLogin)
            {
                using (CurrentPrincipalAccessor.Change(await SignInManager.CreateUserPrincipalAsync(user)))
                {
                    await IdentityLinkUserAppService.LinkAsync(new LinkUserInput
                    {
                        UserId = LinkUserId.Value,
                        TenantId = LinkTenantId,
                        Token = LinkToken
                    });

                    await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
                    {
                        Identity = IdentitySecurityLogIdentityConsts.Identity,
                        Action = IdentityProSecurityLogActionConsts.LinkUser,
                        UserName = user.UserName,
                        ExtraProperties =
                            {
                                { IdentityProSecurityLogActionConsts.LinkTargetTenantId, LinkTenantId },
                                { IdentityProSecurityLogActionConsts.LinkTargetUserId, LinkUserId }
                            }
                    });

                    using (CurrentTenant.Change(LinkTenantId))
                    {
                        var targetUser = await UserManager.GetByIdAsync(LinkUserId.Value);
                        using (CurrentPrincipalAccessor.Change(await SignInManager.CreateUserPrincipalAsync(targetUser)))
                        {
                            await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
                            {
                                Identity = IdentitySecurityLogIdentityConsts.Identity,
                                Action = IdentityProSecurityLogActionConsts.LinkUser,
                                UserName = targetUser.UserName,
                                ExtraProperties =
                                    {
                                        { IdentityProSecurityLogActionConsts.LinkTargetTenantId, targetUser.TenantId },
                                        { IdentityProSecurityLogActionConsts.LinkTargetUserId, targetUser.Id }
                                    }
                            });
                        }
                    }
                }
            }

            await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
            {
                Identity = IdentitySecurityLogIdentityConsts.IdentityExternal,
                Action = result.ToIdentitySecurityLogAction(),
                UserName = user.UserName
            });

            return RedirectSafely(returnUrl, returnUrlHash);
        }

        var email = loginInfo.Principal.FindFirstValue(AbpClaimTypes.Email);
        if (email.IsNullOrWhiteSpace())
        {
            return RedirectToPage("./Register", new {
                IsExternalLogin = true,
                ExternalLoginAuthSchema = loginInfo.LoginProvider,
                ReturnUrl = returnUrl
            });
        }
        
        //-------- this is the source code, you can change it.------------
        var externalUser = await UserManager.FindByEmailAsync(email);
        if (externalUser == null)
        {
            externalUser = await CreateExternalUserAsync(loginInfo);
        }
        else
        {
            if (await UserManager.FindByLoginAsync(loginInfo.LoginProvider, loginInfo.ProviderKey) == null)
            {
                CheckIdentityErrors(await UserManager.AddLoginAsync(externalUser, loginInfo));
            }
        }

        if (await HasRequiredIdentitySettings())
        {
            Logger.LogWarning($"New external user is created but confirmation is required!");

            await StoreConfirmUser(externalUser);
            return RedirectToPage("./ConfirmUser", new {
                returnUrl = ReturnUrl,
                returnUrlHash = ReturnUrlHash
            });
        }

        await SignInManager.SignInAsync(externalUser, false);

        if (IsLinkLogin)
        {
            using (CurrentPrincipalAccessor.Change(await SignInManager.CreateUserPrincipalAsync(externalUser)))
            {
                await IdentityLinkUserAppService.LinkAsync(new LinkUserInput
                {
                    UserId = LinkUserId.Value,
                    TenantId = LinkTenantId,
                    Token = LinkToken
                });

                await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
                {
                    Identity = IdentitySecurityLogIdentityConsts.Identity,
                    Action = IdentityProSecurityLogActionConsts.LinkUser,
                    UserName = externalUser.UserName,
                    ExtraProperties =
                        {
                            { IdentityProSecurityLogActionConsts.LinkTargetTenantId, LinkTenantId },
                            { IdentityProSecurityLogActionConsts.LinkTargetUserId, LinkUserId }
                        }
                });

                using (CurrentTenant.Change(LinkTenantId))
                {
                    var targetUser = await UserManager.GetByIdAsync(LinkUserId.Value);
                    using (CurrentPrincipalAccessor.Change(await SignInManager.CreateUserPrincipalAsync(targetUser)))
                    {
                        await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
                        {
                            Identity = IdentitySecurityLogIdentityConsts.Identity,
                            Action = IdentityProSecurityLogActionConsts.LinkUser,
                            UserName = targetUser.UserName,
                            ExtraProperties =
                                {
                                    { IdentityProSecurityLogActionConsts.LinkTargetTenantId, targetUser.TenantId },
                                    { IdentityProSecurityLogActionConsts.LinkTargetUserId, targetUser.Id }
                                }
                        });
                    }
                }
            }
        }

        await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
        {
            Identity = IdentitySecurityLogIdentityConsts.IdentityExternal,
            Action = result.ToIdentitySecurityLogAction(),
            UserName = externalUser.Name
        });

        return RedirectSafely(returnUrl, returnUrlHash);
    }
}

it will still attempt to find the user every time and not be able to find it

Sorry, I didn't get it.

Hi,

Do not throw exceptions, this may cause the lock to not be released

We need to use it in all entities in our project as create and update, which causes code repetition. I wonder if you have a solution for this?

You can create a generic domain service:

public class LockEntityManager<TEntity> where TEntity: .... , ITransientDependency
{
    private readonly IRepository<TEntity> _reopsitory;
    private readonly IAbpDistributedLock _distributedLock;
    private readonly IEntityCheck<TEntity> _entityCheck;
    
    ...
    
    public async Task<TEntity> CreateAsync(TEntity entity, string lockName)
    {
       await using (var handle = 
                         await _distributedLock.TryAcquireAsync(lockName))
        {
            if (handle != null)
            {
               await _entityCheck.CreateValidAsync(entity);
               .....
            }
        }   
    }
    
    public async Task<TEntity> UpdateAsync(TEntity entity, string lockName)
    {
       .....
    }
    
}

public interface IEntityCheck<TEntity> where TEntity: ....
{
     Task CreateValidAsync(Tentity entity);
     
     Task UpdateValidAsync(Tentity entity);
}

public class TestEntityCheck : IEntityCheck<Test>, ITransientDependency
{
      .....
}



public class TestAppService : ...
{
      private readonly LockEntityManager<Test> _testEntityManager;
      
      ....
}
Showing 2961 to 2970 of 6692 entries
Learn More, Pay Less
33% OFF
All Trainings!
Get Your Deal
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.0.0-preview. Updated on September 12, 2025, 10:20