Activities of "LiSong"

ok, but AbpReCaptchaOptions could not be found

Works correctly in production server, but in local development environment, siteverify always returns a low score, causing validation to fail with error message: ** Verification failed, score below threshold**

I have added localhost in the domain list on the google reCAPTCHA key page

I have a hangfilre job: public class HourlyBackgroundWorker : HangfireBackgroundWorkerBase { private readonly ILogger<HourlyBackgroundWorker> _logger; private readonly IUserFileFeedbackService _userFileFeedbackService; private readonly IDataConnectionUserAnswerService _dataConnectionUserAnswerService; private readonly IDataConnectionUserAnswerRepository _dataConnectionUserAnswerRepository; private readonly IFeedbackFilesUpdaterService _feedbackFilesUpdaterService;

public HourlyBackgroundWorker(ILogger&lt;HourlyBackgroundWorker&gt; logger, 
    IUserFileFeedbackService userFileFeedbackService,
    IDataConnectionUserAnswerService dataConnectionUserAnswerService,
    IDataConnectionUserAnswerRepository dataConnectionUserAnswerRepository,
    IFeedbackFilesUpdaterService feedbackFilesUpdaterService)
{
    RecurringJobId = nameof(HourlyBackgroundWorker);
    CronExpression = Cron.Hourly();
    _logger = logger;
    _userFileFeedbackService = userFileFeedbackService;
    _dataConnectionUserAnswerService = dataConnectionUserAnswerService;
    _dataConnectionUserAnswerRepository = dataConnectionUserAnswerRepository;
    _feedbackFilesUpdaterService = feedbackFilesUpdaterService;
}

public override async Task DoWorkAsync(CancellationToken cancellationToken = default)
{
    using var uow = LazyServiceProvider.LazyGetRequiredService&lt;IUnitOfWorkManager&gt;().Begin();
    _logger.LogInformation("Hangfire:HourlyBackgroundWorker::UpdateFeedbacks");
    await _feedbackFilesUpdaterService.UpdateAllFeedbacksAsync();
}

Is Hangfire multi-tenant aware by default? does this hourly job runs for each tenant? i.e. runs once per tenant?

Answer

I ended up creating my own distributed lock using redis, and it worked

Answer

sorry, had to create 3 posts, it was too long, so if you checked the screenshot, the types are correct. but still not working,

Answer

using System.IO; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Tapp.EntityFrameworkCore; using Tapp.Localization; using Tapp.MultiTenancy; using Tapp.Permissions; using Tapp.Web.Menus; using Microsoft.OpenApi.Models; using Volo.Abp; using Volo.Abp.Studio; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX; using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Bundling; using Volo.Abp.LeptonX.Shared; using Volo.Abp.Autofac; using Volo.Abp.AutoMapper; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement; using Volo.Abp.PermissionManagement.Web; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.UI; using Volo.Abp.UI.Navigation; using Volo.Abp.VirtualFileSystem; using Volo.Abp.Identity.Web; using Volo.Abp.FeatureManagement; using OpenIddict.Server.AspNetCore; using OpenIddict.Validation.AspNetCore; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Commercial; using Tapp.Web.HealthChecks; using Volo.Abp.Account.Admin.Web; using Volo.Abp.Account.Public.Web; using Volo.Abp.Account.Public.Web.ExternalProviders; using Volo.Abp.Account.Pro.Public.Web.Shared; using Volo.Abp.AuditLogging.Web; using Volo.Abp.LanguageManagement; using Volo.Abp.TextTemplateManagement.Web; using Volo.Saas.Host; using Volo.Abp.Gdpr.Web; using Volo.Abp.Gdpr.Web.Extensions; using Volo.Abp.OpenIddict.Pro.Web; using System; using System.Security.Cryptography.X509Certificates; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authentication.MicrosoftAccount; using Microsoft.AspNetCore.Authentication.Twitter; using Microsoft.AspNetCore.Extensions.DependencyInjection; using Volo.Abp.Account.Web; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars; using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Identity; using Volo.Abp.Swashbuckle; using Volo.Abp.OpenIddict; using Volo.Abp.Security.Claims; using Volo.Abp.SettingManagement.Web; using Volo.Abp.Studio.Client.AspNetCore; using Medallion.Threading; using StackExchange.Redis; using Medallion.Threading.Redis; using Volo.Abp.DistributedLocking;

namespace Tapp.Web;

[DependsOn( typeof(AbpDistributedLockingModule), typeof(TappHttpApiModule), typeof(TappApplicationModule), typeof(TappEntityFrameworkCoreModule), typeof(AbpAutofacModule), typeof(AbpStudioClientAspNetCoreModule), typeof(AbpIdentityWebModule), typeof(AbpAspNetCoreMvcUiLeptonXThemeModule), typeof(AbpAccountPublicWebOpenIddictModule), typeof(AbpAuditLoggingWebModule), typeof(SaasHostWebModule), typeof(AbpAccountAdminWebModule), typeof(AbpOpenIddictProWebModule), typeof(LanguageManagementWebModule), typeof(TextTemplateManagementWebModule), typeof(AbpGdprWebModule), typeof(AbpFeatureManagementWebModule), typeof(AbpSwashbuckleModule), typeof(AbpAspNetCoreSerilogModule) )] public class TappWebModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); var configuration = context.Services.GetConfiguration();

    context.Services.PreConfigure&lt;AbpMvcDataAnnotationsLocalizationOptions&gt;(options =>
    {
        options.AddAssemblyResource(
            typeof(TappResource),
            typeof(TappDomainModule).Assembly,
            typeof(TappDomainSharedModule).Assembly,
            typeof(TappApplicationModule).Assembly,
            typeof(TappApplicationContractsModule).Assembly,
            typeof(TappWebModule).Assembly
        );
    });

    PreConfigure&lt;OpenIddictBuilder&gt;(builder =>
    {
        builder.AddValidation(options =>
        {
            options.AddAudiences("Tapp");
            options.UseLocalServer();
            options.UseAspNetCore();
        });
    });

    if (!hostingEnvironment.IsDevelopment())
    {
        PreConfigure&lt;AbpOpenIddictAspNetCoreOptions&gt;(options =>
        {
            options.AddDevelopmentEncryptionAndSigningCertificate = false;
        });

        PreConfigure&lt;OpenIddictServerBuilder&gt;(serverBuilder =>
        {
            serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", configuration["AuthServer:CertificatePassPhrase"]!);
            serverBuilder.SetIssuer(new Uri(configuration["AuthServer:Authority"]!));
        });
    }
}

public override void ConfigureServices(ServiceConfigurationContext context)
{
    var hostingEnvironment = context.Services.GetHostingEnvironment();
    var configuration = context.Services.GetConfiguration();

    if (!configuration.GetValue&lt;bool&gt;("App:DisablePII"))
    {
        Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
        Microsoft.IdentityModel.Logging.IdentityModelEventSource.LogCompleteSecurityArtifact = true;
    }

    if (!configuration.GetValue&lt;bool&gt;("AuthServer:RequireHttpsMetadata"))
    {
        Configure&lt;OpenIddictServerAspNetCoreOptions&gt;(options =>
        {
            options.DisableTransportSecurityRequirement = true;
        });
        
        Configure&lt;ForwardedHeadersOptions&gt;(options =>
        {
            options.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
        });
    }

    context.Services.AddSingleton&lt;IDistributedLockProvider&gt;(sp =>
    {
        var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
        return new RedisDistributedSynchronizationProvider(connection.GetDatabase());
    });

    ConfigureBundles();
    ConfigureUrls(configuration);
    ConfigurePages(configuration);
    ConfigureImpersonation(context, configuration);
    ConfigureHealthChecks(context);
    ConfigureExternalProviders(context);
    ConfigureCookieConsent(context);
    ConfigureAuthentication(context);
    ConfigureAutoMapper();
    ConfigureVirtualFileSystem(hostingEnvironment);
    ConfigureNavigationServices();
    ConfigureAutoApiControllers();
    ConfigureSwaggerServices(context.Services);
    ConfigureTheme();

    Configure&lt;PermissionManagementOptions&gt;(options =>
    {
        options.IsDynamicPermissionStoreEnabled = true;
    });
}

private void ConfigureCookieConsent(ServiceConfigurationContext context)
{
    context.Services.AddAbpCookieConsent(options =>
    {
        options.IsEnabled = true;
        options.CookiePolicyUrl = "/CookiePolicy";
        options.PrivacyPolicyUrl = "/PrivacyPolicy";
    });
}

private void ConfigureTheme()
{
    Configure&lt;LeptonXThemeOptions&gt;(options =>
    {
        options.DefaultStyle = LeptonXStyleNames.System;
    });

    Configure&lt;LeptonXThemeMvcOptions&gt;(options =>
    {
        options.ApplicationLayout = LeptonXMvcLayouts.SideMenu;
    });
}

private void ConfigureHealthChecks(ServiceConfigurationContext context)
{
    context.Services.AddTappHealthChecks();
}

private void ConfigureBundles()
{
    Configure&lt;AbpBundlingOptions&gt;(options =>
    {
        options.StyleBundles.Configure(
            LeptonXThemeBundles.Styles.Global,
            bundle =>
            {
                bundle.AddFiles("/global-scripts.js");
                bundle.AddFiles("/global-styles.css");
            }
        );
    });
}

private void ConfigurePages(IConfiguration configuration)
{
    Configure&lt;RazorPagesOptions&gt;(options =>
    {
        options.Conventions.AuthorizePage("/HostDashboard", TappPermissions.Dashboard.Host);
        options.Conventions.AuthorizePage("/TenantDashboard", TappPermissions.Dashboard.Tenant);
    });
}

private void ConfigureUrls(IConfiguration configuration)
{
    Configure&lt;AppUrlOptions&gt;(options =>
    {
        options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
    });
}

private void ConfigureAuthentication(ServiceConfigurationContext context)
{
    context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
    context.Services.Configure&lt;AbpClaimsPrincipalFactoryOptions&gt;(options =>
    {
        options.IsDynamicClaimsEnabled = true;
    });
}

private void ConfigureImpersonation(ServiceConfigurationContext context, IConfiguration configuration)
{
    context.Services.Configure&lt;AbpSaasHostWebOptions&gt;(options =>
    {
        options.EnableTenantImpersonation = true;
    });
    context.Services.Configure&lt;AbpIdentityWebOptions&gt;(options =>
    {
        options.EnableUserImpersonation = true;
    });
    context.Services.Configure&lt;AbpAccountOptions&gt;(options =>
    {
        options.TenantAdminUserName = "admin";
        options.ImpersonationTenantPermission = SaasHostPermissions.Tenants.Impersonation;
        options.ImpersonationUserPermission = IdentityPermissions.Users.Impersonation;
    });
}

private void ConfigureAutoMapper()
{
    Configure&lt;AbpAutoMapperOptions&gt;(options =>
    {
        options.AddMaps&lt;TappWebModule&gt;();
    });
}

private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
{
    Configure&lt;AbpVirtualFileSystemOptions&gt;(options =>
    {
        options.FileSets.AddEmbedded&lt;TappWebModule&gt;();

        if (hostingEnvironment.IsDevelopment())
        {
            options.FileSets.ReplaceEmbeddedByPhysical&lt;TappDomainSharedModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Tapp.Domain.Shared", Path.DirectorySeparatorChar)));
            options.FileSets.ReplaceEmbeddedByPhysical&lt;TappDomainModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Tapp.Domain", Path.DirectorySeparatorChar)));
            options.FileSets.ReplaceEmbeddedByPhysical&lt;TappApplicationContractsModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Tapp.Application.Contracts", Path.DirectorySeparatorChar)));
            options.FileSets.ReplaceEmbeddedByPhysical&lt;TappApplicationModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Tapp.Application", Path.DirectorySeparatorChar)));
            options.FileSets.ReplaceEmbeddedByPhysical&lt;TappHttpApiModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}Tapp.HttpApi", Path.DirectorySeparatorChar)));
            options.FileSets.ReplaceEmbeddedByPhysical&lt;TappWebModule&gt;(hostingEnvironment.ContentRootPath);
        }
    });
}

private void ConfigureNavigationServices()
{
    Configure&lt;AbpNavigationOptions&gt;(options =>
    {
        options.MenuContributors.Add(new TappMenuContributor());
    });

    Configure&lt;AbpToolbarOptions&gt;(options =>
    {
        options.Contributors.Add(new TappToolbarContributor());
    });
}

private void ConfigureAutoApiControllers()
{
    Configure&lt;AbpAspNetCoreMvcOptions&gt;(options =>
    {
        options.ConventionalControllers.Create(typeof(TappApplicationModule).Assembly);
    });
}

private void ConfigureSwaggerServices(IServiceCollection services)
{
    services.AddAbpSwaggerGen(
        options =>
        {
            options.SwaggerDoc("v1", new OpenApiInfo { Title = "Tapp API", Version = "v1" });
            options.DocInclusionPredicate((docName, description) => true);
            options.CustomSchemaIds(type => type.FullName);
        }
    );
}

private void ConfigureExternalProviders(ServiceConfigurationContext context)
{
    context.Services.AddAuthentication()
        .AddGoogle(GoogleDefaults.AuthenticationScheme, options =>
        {
            options.ClaimActions.MapJsonKey(AbpClaimTypes.Picture, "picture");
        })
        .WithDynamicOptions&lt;GoogleOptions, GoogleHandler&gt;(
            GoogleDefaults.AuthenticationScheme,
            options =>
            {
                options.WithProperty(x => x.ClientId);
                options.WithProperty(x => x.ClientSecret, isSecret: true);
            }
        )
        .AddMicrosoftAccount(MicrosoftAccountDefaults.AuthenticationScheme, options =>
        {
            //Personal Microsoft accounts as an example.
            options.AuthorizationEndpoint = "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize";
            options.TokenEndpoint = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";

            options.ClaimActions.MapCustomJson("picture", _ => "https://graph.microsoft.com/v1.0/me/photo/$value");
            options.SaveTokens = true;
        })
        .WithDynamicOptions&lt;MicrosoftAccountOptions, MicrosoftAccountHandler&gt;(
            MicrosoftAccountDefaults.AuthenticationScheme,
            options =>
            {
                options.WithProperty(x => x.ClientId);
                options.WithProperty(x => x.ClientSecret, isSecret: true);
            }
        )
        .AddTwitter(TwitterDefaults.AuthenticationScheme, options =>
        {
            options.ClaimActions.MapJsonKey(AbpClaimTypes.Picture,"profile_image_url_https");
            options.RetrieveUserDetails = true;
        })
        .WithDynamicOptions&lt;TwitterOptions, TwitterHandler&gt;(
            TwitterDefaults.AuthenticationScheme,
            options =>
            {
                options.WithProperty(x => x.ConsumerKey);
                options.WithProperty(x => x.ConsumerSecret, isSecret: true);
            }
        );
}


public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
    var app = context.GetApplicationBuilder();
    var env = context.GetEnvironment();

    app.UseForwardedHeaders();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseAbpRequestLocalization();

    if (!env.IsDevelopment())
    {
        app.UseErrorPage();
        app.UseHsts();
    }

    app.UseAbpCookieConsent();
    app.UseCorrelationId();
    app.MapAbpStaticAssets();
    app.UseAbpStudioLink();
    app.UseRouting();
    app.UseAbpSecurityHeaders();
    app.UseAuthentication();
    app.UseAbpOpenIddictValidation();

    if (MultiTenancyConsts.IsEnabled)
    {
        app.UseMultiTenancy();
    }

    app.UseUnitOfWork();
    app.UseDynamicClaims();
    app.UseAuthorization();
    app.UseSwagger();
    app.UseAbpSwaggerUI(options =>
    {
        options.SwaggerEndpoint("/swagger/v1/swagger.json", "Tapp API");
    });
    app.UseAuditing();
    app.UseAbpSerilogEnrichers();
    app.UseConfiguredEndpoints();
}

}

Answer

still not working, pls take a look:

using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System.Threading.Tasks; using System; using Volo.Abp.DistributedLocking; using Medallion.Threading;

namespace Tapp.Web.Pages;

public class IndexModel : TappPageModel { private readonly IAbpDistributedLock _distributedLock; private readonly IDistributedLockProvider _distributedLockProvider; private readonly ILogger<IndexModel> _logger;

public IndexModel(IAbpDistributedLock distributedLock, IDistributedLockProvider distributedLockProvider, ILogger&lt;IndexModel&gt; logger)
{
    _distributedLock = distributedLock;
    _distributedLockProvider = distributedLockProvider;
    _logger = logger;
}

public string LockTestResult { get; set; }
public virtual async Task&lt;IActionResult&gt; OnGetAsync()
{
    await RunLockTestAsync();
    return Page();
}

private async Task RunLockTestAsync()
{
    var currentUserId = Guid.NewGuid(); // For testing, generate a dummy user id
    var lockKey = $"form-submission-lock:";
    for (int i = 0; i &lt; 3; i++)
    {
        await using var handle = await _distributedLock.TryAcquireAsync(lockKey, TimeSpan.FromSeconds(5));
        if (handle != null)
        {
            await DummyCriticalSection();
            _logger.LogInformation(&quot;Lock acquired and dummy section executed.&quot;);
            //return &quot;Lock acquired and dummy section executed.&quot;;
        }
        else
        {
            _logger.LogWarning(&quot;Could not acquire lock, retrying...&quot;);
        }

    }
    _logger.LogError(&quot;Could not acquire lock after 3 attempts.&quot;);
    //return &quot;Could not acquire lock after 3 attempts.&quot;;
}

private async Task DummyCriticalSection()
{
    await Task.Delay(1000); // Simulate work
}

}

<ItemGroup> <PackageReference Include="AspNetCore.HealthChecks.UI" Version="9.0.0" /> <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="9.0.0" /> <PackageReference Include="DistributedLock.Core" Version="1.0.8" /> <PackageReference Include="DistributedLock.Redis" Version="1.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0" /> <PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="9.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" /> <PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="9.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.Twitter" Version="9.0.0" /> <PackageReference Include="StackExchange.Redis" Version="2.8.58" /> <PackageReference Include="Volo.Abp.DistributedLocking" Version="9.0.4" /> </ItemGroup>

Answer

just sent you an email with the project thanks

Answer

I have set up the breakpoints, and I confirm

the Type of _distributedLock is MedallionAbpDistributedLock.

the IDistributedLockProvider is RedisDistributedSynchronizationProvider

but the lock still doesnt work

Answer

thanks I am checking

Showing 31 to 40 of 124 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on October 21, 2026, 11:09
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.