Base solution for your next web application
Open Closed

Using SettingManager in Hangfire Job #6478


User avatar
0
firnas created

Hi,

I have a hangfire job which calls a class in the Core project. This class calls the settings manager to get a setting value.

string dealerNo = await _settingManager.GetSettingValueAsync(MyConstants.DealerNo);

This returns a empty string as the dealer no. Is there any configuration that needs to be done to get Settings manager to work with hangfire?


22 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team

    Is MyConstants.DealerNo setting related to tenants and users?

  • User Avatar
    0
    firnas created

    Its related to Tenant

  • User Avatar
    0
    maliming created
    Support Team

    You can inject the session and see. I guess there is no tenant id currently, so you got the wrong return value.

  • User Avatar
    0
    firnas created

    I injected the AbpSession but the tenant id returned is null.

    i enclosed the code block in the using statement. as below,

    `using (_unitOfWorkManager.Current.SetTenantId(_abpSession.TenantId)) {

    }`

  • User Avatar
    0
    maliming created
    Support Team

    Yes, the background job has no session information. You can pass TenantId to the background job and then set the TenantId of the current session (also for userid)

    see: https://aspnetboilerplate.com/Pages/Documents/Abp-Session#overriding-current-session-values

  • User Avatar
    0
    firnas created

    Tha job is a recurring job and i have registerd it in the WebCoreModule. How can i then pass in the tenant id?

  • User Avatar
    0
    maliming created
    Support Team

    Please share your code (including AppSettingProvider)

  • User Avatar
    0
    firnas created

    Below is the App setting code,

    public static class PasstimeManagement { public const string PasstimeAddress = "PasstimeAddress"; public const string Password = "App.Passtime.Password"; public const string UserName = "App.Passtime.UserName"; public const string DealerNo = "App.Passtime.DealerNo"; }

    Below is the App settings provider code,

    private IEnumerable<SettingDefinition> GetPasstimeSettings() { return new[] { new SettingDefinition(AppSettings.PasstimeManagement.PasstimeAddress, GetFromAppSettings(AppSettings.PasstimeManagement.PasstimeAddress)), new SettingDefinition(AppSettings.PasstimeManagement.Password, GetFromAppSettings(AppSettings.PasstimeManagement.Password, ""), scopes: SettingScopes.Tenant), new SettingDefinition(AppSettings.PasstimeManagement.UserName, GetFromAppSettings(AppSettings.PasstimeManagement.UserName, ""), scopes: SettingScopes.Tenant), new SettingDefinition(AppSettings.PasstimeManagement.DealerNo, GetFromAppSettings(AppSettings.PasstimeManagement.DealerNo, ""), scopes: SettingScopes.Tenant) }; }

    Below is the code in the job,

    [UnitOfWork] public virtual async Task SendDeviceUnlockNotification() { using (_unitOfWorkManager.Current.SetTenantId(_abpSession.TenantId)) { string dealerNo = await _settingManager.GetSettingValueAsync(PasstimeManagement.DealerNo); ///more lines below } }

  • User Avatar
    0
    maliming created
    Support Team

    What is the function of the SendDeviceUnlockNotification method? Is it a notification to all tenants?

  • User Avatar
    0
    firnas created

    This function should run periodically and check the database for device unlock requests. When a record is found, the job should pick it up and call a external service to unlock the device. The parameters for the request is stored tenant wise. (e.g. the dealer no is chaning from tenant to tenant).

    If the device is unlocked, then a push notification is sent via App center to the mobile.

  • User Avatar
    0
    maliming created
    Support Team

    The problem now is that this requires the correct tenant ID (because you need to get the settings for this tenant), can you get the tenant ID via device unlock requests?

    Then call using (_unitOfWorkManager.Current.SetTenantId(YourTenantId))

  • User Avatar
    0
    firnas created

    No. The external service does not have the tenant id.

  • User Avatar
    0
    maliming created
    Support Team

    I don't know your specific business. As I said above, if you want to get the tenant's settings you need to find a way to get TenantId.

  • User Avatar
    0
    firnas created

    I hardcoded the tenant id for testing as below,

    _unitOfWorkManager.Current.SetTenantId(2)

    but still the setting value is empty.

  • User Avatar
    0
    maliming created
    Support Team

    You can see if there is a setting information for the tenant with id 2 in the AbpSettings table of the database.

  • User Avatar
    0
    firnas created

    Yes there is a setting. still the setting is not returned

  • User Avatar
    0
    maliming created
    Support Team

    Do you have a Telegram or skype?

  • User Avatar
    0
    aaron created
    Support Team

    Show screenshot of records in database.

  • User Avatar
    0
    firnas created

    Hi,

    I got the code to work partially. i was able to set the tenant using the _abpSession.Use(2, null) hardcoding 2 as the tenant id for debugging. and it worked.

    I can get the Tenant id from the User table. The Payment entity has a loan mapped to it. The Loan has the User. So now when i want to get the user using usermanager, since it is outside the unit of work manager (i guess), I am getting a error stating that the user id is not found. But user id is available in the table.

    //get the tenant id for the payment User user = await _userManager.GetUserByIdAsync(payment.Loan.UserId);

    Is there a way i can include the User as well when i am getting the payment detiails. There is a navigation property to User table from the loan object.

    Payment -> Loan -> User

    Any help is highly appriciated.

    [UnitOfWork] public virtual async Task SendDeviceUnlockNotification() { try { //get the device unlock requests from the db IList<Payment> payments = _paymentRepository.GetAllIncluding(p => p.Loan).Where(p => p.DeviceUnlockStatus == "Requested").ToList(); //loop through the payments and check the device unlock status foreach (Payment payment in payments) { //get the tenant id for the payment User user = await _userManager.GetUserByIdAsync(payment.Loan.UserId);

                    using (_abpSession.Use(user.TenantId, null))
                    {
                        using (_unitOfWorkManager.Current.SetTenantId(_abpSession.TenantId))
                        {
                            string status = await _passtimeDomainService.GetDeviceStatus(payment.Loan.VIN);
                            if (status.ToLower() == "enabled")
                            {
                                //update the device unlock status
                                payment.DeviceUnlockStatus = "Unlocked";
                                await _paymentRepository.UpdateAsync(payment);
    
                                //send push notification
                                NotificationData notificationData = new NotificationData
                                {
                                    UserName = user.UserName,
                                    Name = "Vehicle Unlocked Notification",
                                    Title = "Vehicle Unlocked",
                                    Body = "Your vehicle has been unlocked"
                                };
                                await _appCentre.NotifyAsync(notificationData);
                            }
    
    
    
                        }
                    }
                }
                _unitOfWorkManager.Current.SaveChanges();
            }
            catch (Exception ex)
            {
                //log any exception
            }
        }
    
  • User Avatar
    0
    firnas created

    I managed to get this to work. I disabled the filters in the unit of work manager. Then it returned the user.

    _unitOfWorkManager.Current.DisableFilter("MayHaveTenant", "MustHaveTenant"); //get the tenant id for the payment User user = await _userManager.Users.Where(u=>u.Id == payment.Loan.UserId).FirstOrDefaultAsync();

    Please let me know any issues in the above solution.

  • User Avatar
    0
    aaron created
    Support Team

    It is fine, but will not work if you use multiple (tenant-specific) databases.

  • User Avatar
    0
    firnas created

    I am using single database. so i think i will not run into a problem.

    Thanks All for the support.