sorry, had to create 3 posts, it was too long, so if you checked the screenshot, the types are correct. but still not working,
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<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(
typeof(TappResource),
typeof(TappDomainModule).Assembly,
typeof(TappDomainSharedModule).Assembly,
typeof(TappApplicationModule).Assembly,
typeof(TappApplicationContractsModule).Assembly,
typeof(TappWebModule).Assembly
);
});
PreConfigure<OpenIddictBuilder>(builder =>
{
builder.AddValidation(options =>
{
options.AddAudiences("Tapp");
options.UseLocalServer();
options.UseAspNetCore();
});
});
if (!hostingEnvironment.IsDevelopment())
{
PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
{
options.AddDevelopmentEncryptionAndSigningCertificate = false;
});
PreConfigure<OpenIddictServerBuilder>(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<bool>("App:DisablePII"))
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
Microsoft.IdentityModel.Logging.IdentityModelEventSource.LogCompleteSecurityArtifact = true;
}
if (!configuration.GetValue<bool>("AuthServer:RequireHttpsMetadata"))
{
Configure<OpenIddictServerAspNetCoreOptions>(options =>
{
options.DisableTransportSecurityRequirement = true;
});
Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
});
}
context.Services.AddSingleton<IDistributedLockProvider>(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<PermissionManagementOptions>(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<LeptonXThemeOptions>(options =>
{
options.DefaultStyle = LeptonXStyleNames.System;
});
Configure<LeptonXThemeMvcOptions>(options =>
{
options.ApplicationLayout = LeptonXMvcLayouts.SideMenu;
});
}
private void ConfigureHealthChecks(ServiceConfigurationContext context)
{
context.Services.AddTappHealthChecks();
}
private void ConfigureBundles()
{
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(
LeptonXThemeBundles.Styles.Global,
bundle =>
{
bundle.AddFiles("/global-scripts.js");
bundle.AddFiles("/global-styles.css");
}
);
});
}
private void ConfigurePages(IConfiguration configuration)
{
Configure<RazorPagesOptions>(options =>
{
options.Conventions.AuthorizePage("/HostDashboard", TappPermissions.Dashboard.Host);
options.Conventions.AuthorizePage("/TenantDashboard", TappPermissions.Dashboard.Tenant);
});
}
private void ConfigureUrls(IConfiguration configuration)
{
Configure<AppUrlOptions>(options =>
{
options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
});
}
private void ConfigureAuthentication(ServiceConfigurationContext context)
{
context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true;
});
}
private void ConfigureImpersonation(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.Configure<AbpSaasHostWebOptions>(options =>
{
options.EnableTenantImpersonation = true;
});
context.Services.Configure<AbpIdentityWebOptions>(options =>
{
options.EnableUserImpersonation = true;
});
context.Services.Configure<AbpAccountOptions>(options =>
{
options.TenantAdminUserName = "admin";
options.ImpersonationTenantPermission = SaasHostPermissions.Tenants.Impersonation;
options.ImpersonationUserPermission = IdentityPermissions.Users.Impersonation;
});
}
private void ConfigureAutoMapper()
{
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<TappWebModule>();
});
}
private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<TappWebModule>();
if (hostingEnvironment.IsDevelopment())
{
options.FileSets.ReplaceEmbeddedByPhysical<TappDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Tapp.Domain.Shared", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<TappDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Tapp.Domain", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<TappApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Tapp.Application.Contracts", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<TappApplicationModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Tapp.Application", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<TappHttpApiModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}Tapp.HttpApi", Path.DirectorySeparatorChar)));
options.FileSets.ReplaceEmbeddedByPhysical<TappWebModule>(hostingEnvironment.ContentRootPath);
}
});
}
private void ConfigureNavigationServices()
{
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new TappMenuContributor());
});
Configure<AbpToolbarOptions>(options =>
{
options.Contributors.Add(new TappToolbarContributor());
});
}
private void ConfigureAutoApiControllers()
{
Configure<AbpAspNetCoreMvcOptions>(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<GoogleOptions, GoogleHandler>(
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<MicrosoftAccountOptions, MicrosoftAccountHandler>(
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<TwitterOptions, TwitterHandler>(
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();
}
}
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<IndexModel> logger)
{
_distributedLock = distributedLock;
_distributedLockProvider = distributedLockProvider;
_logger = logger;
}
public string LockTestResult { get; set; }
public virtual async Task<IActionResult> 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 < 3; i++)
{
await using var handle = await _distributedLock.TryAcquireAsync(lockKey, TimeSpan.FromSeconds(5));
if (handle != null)
{
await DummyCriticalSection();
_logger.LogInformation("Lock acquired and dummy section executed.");
//return "Lock acquired and dummy section executed.";
}
else
{
_logger.LogWarning("Could not acquire lock, retrying...");
}
}
_logger.LogError("Could not acquire lock after 3 attempts.");
//return "Could not acquire lock after 3 attempts.";
}
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>
just sent you an email with the project thanks
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
thanks I am checking
ok. thx
I don't see the code in the whole solution, I've actually searched for 'ConfigureCors' in the entire solution but found 0 matches, do I need to add the configurecors function myself? I want to clarify this to make sure I don't override anything underlying that might compromise security. thanks
sorry, I am using a layered application and non-Tiered, I was confused by layered and tiered. do you mind also checking the layered application for me. thanks
yes, it's a CORS error, I ran this command: curl -i -X OPTIONS https://localhost:44381/api/app/ethnicities -H 'Origin: http://localhost:5173' -H 'Access-Control-Request-Method: GET'
and got C:\Users\songh>curl -i -X OPTIONS https://localhost:44381/api/app/ethnicities -H "Origin: http://localhost:5173" -H "Access-Control-Request-Method: GET" HTTP/1.1 405 Method Not Allowed Transfer-Encoding: chunked Allow: GET, HEAD, POST Server: Microsoft-IIS/10.0 X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN X-Correlation-Id: 3880f62679854d47a73e1b5cff09a43c X-SourceFiles: =?UTF-8?B?RDpcZ2l0XHRhcHAtOVxzcmNcVGFwcC5XZWJcYXBpXGFwcFxldGhuaWNpdGllcw==?= Date: Tue, 08 Apr 2025 23:14:45 GMT