Thanks your helping, maliming
[maliming] said: hi
The UserFriendlyException not shown on the razor page client
What is your razor page code?
Thanks
Not any specified code, just a form submit, send a phonenumber and a verification code to API side.
ABP ver 9.3.5 with micro-services architecture, the UserFriendlyException not shown on the razor page client when backend API throw a UserFriendlyException, below is the code section:
A BusinessException threw but it cannot shown on the client side in a application service like below:
`
public virtual async Task
if (!result)
{
throw new InvalidVerificationCodeException();
}
var identityUser = await _phoneNumberLoginNewUserCreator.CreateAsync(input.PhoneNumber, input.UserName, input.Password, input.EmailAddress);
return ObjectMapper.Map<IdentityUser, IdentityUserDto>(identityUser);
}
`
the InvalidVerificationCodeException is a BusinessException
I added an UserFriendlyException in the Controller like below:
`
[HttpPost]
[Route("register/by-phone-number")]
public virtual async Task
return result;
}
catch (BusinessException ex)
{
throw new UserFriendlyException(ex.Code);
}
}
`
it got below logs in the backend:
`
2025-10-08 17:38:45.887 +08:00 [WRN] ---------- RemoteServiceErrorInfo ----------
{ "code": null, "message": "EasyAbp.Abp.PhoneNumberLogin:InvalidVerificationCode", "details": null, "data": {}, "validationErrors": null }
2025-10-08 17:38:45.887 +08:00 [WRN] EasyAbp.Abp.PhoneNumberLogin:InvalidVerificationCode Volo.Abp.UserFriendlyException: EasyAbp.Abp.PhoneNumberLogin:InvalidVerificationCode at EasyAbp.Abp.PhoneNumberLogin.Web.Controllers.PhoneNumberLogin.Account.LoginController.RegisterByPhoneNumberAsync(RegisterWithPhoneNumberInput input) at lambda_method3691(Closure, Object) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.
then the client get a 403 forbidden HTTP Status code with the errors like below, it doesn't use UI throw a message:
{ "error": { "code": null, "message": "EasyAbp.Abp.PhoneNumberLogin:InvalidVerificationCode", "details": null, "data": {}, "validationErrors": null } }
Resolved by added below code in ConfigureServices:
`
Configure
// This Cron expression only works if Hangfire or Quartz is used for background workers.
// The Hangfire Cron expression is different from the Quartz Cron expression, Please refer to the following links:
// https://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/crontriggers.html#cron-expressions
// https://docs.hangfire.io/en/latest/background-methods/performing-recurrent-tasks.html
options.CronExpression = "0 2 * * * ?"; // Quartz Cron expression is "0 23 * * * ?"
});
` The default cron expression is for Hangfire, needs to add the correct format for Quartz if you are using Quartz as background worker.
This should add int the doc as a configuration section.
2025-09-28 05:01:50.206 +08:00 [FTL] Host terminated unexpectedly! Volo.Abp.AbpInitializationException: An error occurred during the initialize Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor phase of the module Volo.Abp.AuditLogging.AbpAuditLoggingApplicationModule, Volo.Abp.AuditLogging.Application, Version=9.3.4.0, Culture=neutral, PublicKeyToken=null: Unexpected end of expression.. See the inner exception for details. ---> System.FormatException: Unexpected end of expression. at Quartz.CronExpression.BuildExpression(String expression) at Quartz.CronExpression..ctor(String cronExpression) at Quartz.CronExpression.ValidateExpression(String cronExpression) at Quartz.CronScheduleBuilder.CronSchedule(String cronExpression) at Quartz.CronScheduleTriggerBuilderExtensions.WithCronSchedule(TriggerBuilder triggerBuilder, String cronExpression) at Volo.Abp.BackgroundWorkers.Quartz.QuartzPeriodicBackgroundWorkerAdapter
1.BuildWorker(IBackgroundWorker worker)
at Volo.Abp.BackgroundWorkers.Quartz.QuartzBackgroundWorkerManager.ReScheduleJobAsync(IBackgroundWorker worker, CancellationToken cancellationToken)
at Volo.Abp.BackgroundWorkers.Quartz.QuartzBackgroundWorkerManager.AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken)
at Volo.Abp.AuditLogging.AbpAuditLoggingApplicationModule.OnApplicationInitializationAsync(ApplicationInitializationContext context)
at Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor.InitializeAsync(ApplicationInitializationContext context, IAbpModule module)
at Volo.Abp.Modularity.ModuleManager.InitializeModulesAsync(ApplicationInitializationContext context)
--- End of inner exception stack trace ---
at Volo.Abp.Modularity.ModuleManager.InitializeModulesAsync(ApplicationInitializationContext context)
at Volo.Abp.AbpApplicationBase.InitializeModulesAsync()
at Volo.Abp.AbpApplicationWithExternalServiceProvider.InitializeAsync(IServiceProvider serviceProvider)
at Microsoft.AspNetCore.Builder.AbpApplicationBuilderExtensions.InitializeApplicationAsync(IApplicationBuilder app)
at Viewtance.FM.Program.Main(String[] args) in D:\Source\Repos\apps\Viewtance.FM\src\Viewtance.FM.HttpApi.Host\Program.cs:line 58
`The generate proxy issue resolved, it caused by a typo which the interface of the integration service not follow the conventional.
any miss configuration for integration service, or the generate proxy action is wrong?
Thanks for the help from Maliming, the auth server UI login is a cookie authentication, not the token scenario, added below code auth server module works fine
`
context.Services.ConfigureApplicationCookie(options =>
{
var previousOnSignedIn = options.Events.OnSignedIn;
options.Events.OnSignedIn = async cookieSignedInContext =>
{
await previousOnSignedIn(cookieSignedInContext);
};
var previousOnSigningOut = options.Events.OnSigningOut;
options.Events.OnSigningOut = async cookieSigningOutContext =>
{
await previousOnSigningOut(cookieSigningOutContext);
};
}); `
The simple inline handle is not triggered, the event itself may not be firing due to pipeline misconfiguration, could you give some suggestions which pipeline misconfiguration?
I want to implement some actions (such as given award points to a user daily if the user sign in every day), I need to add an event to OpenIddict server event that it could fire an event handler to implement the logistics, I have followed the article add the event handler and registered in AuthServer project (a micro-services architecture solution), but the event handler not fired and no logs logged, is there any suggestions to debug, or I am using an incorrect way to configure the event handler?
public class DailyPointsHandler : IOpenIddictServerHandler<OpenIddictServerEvents.ProcessSignInContext>//, ITransientDependency
{
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<OpenIddictServerEvents.ProcessSignInContext>()
.UseScopedHandler<DailyPointsHandler>()
.SetOrder(100_000)
.SetType(OpenIddictServerHandlerType.Custom)
.Build();
private readonly IdentityUserManager _userManager;
private readonly IClock _clock;
private readonly ILogger<DailyPointsHandler> _logger;
private readonly IRewardPointsHistoriesAppService _rewardPointsHistoriesAppService;
private readonly IUnitOfWorkManager _unitOfWorkManager;
public DailyPointsHandler(
IdentityUserManager userManager,
IClock clock,
ILogger<DailyPointsHandler> logger,
IRewardPointsHistoriesAppService rewardPointsHistoriesAppService,
IUnitOfWorkManager unitOfWorkManager)
{
_userManager = userManager;
_clock = clock;
_logger = logger;
_rewardPointsHistoriesAppService = rewardPointsHistoriesAppService;
_unitOfWorkManager = unitOfWorkManager;
_logger.LogInformation("DailyPointsHandler constructor initialized");
}
public async ValueTask HandleAsync(OpenIddictServerEvents.ProcessSignInContext context)
{
_logger.LogInformation("进入每日积分处理器");
if (context is null) throw new ArgumentNullException(nameof(context));
// 跳过客户端凭证流程和刷新令牌流程
if (context.Request.IsClientCredentialsGrantType() ||
context.Request.IsRefreshTokenGrantType())
{
_logger.LogInformation("跳过非用户登录流程");
return;
}
// 获取用户ID
var userId = context.Principal?.FindFirst(OpenIddictConstants.Claims.Subject)?.Value;
if (string.IsNullOrEmpty(userId))
{
_logger.LogWarning("无法从声明中获取用户ID");
return;
}
try
{
using var uow = _unitOfWorkManager.Begin(requiresNew: true);
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
_logger.LogWarning("用户未找到: {UserId}", userId);
return;
}
if (user != null)
{
var rewardPointsHistoryCreate = new RewardPointsHistoryCreateDto();
rewardPointsHistoryCreate.UserId = user.Id;
rewardPointsHistoryCreate.RewardPointType = RewardPointType.DailySignIn;
await _rewardPointsHistoriesAppService.CreateAsync(rewardPointsHistoryCreate);
await uow.CompleteAsync();
_logger.LogInformation("用户 {UserName} 获得每日登录奖励", user.UserName);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "每日积分赠送处理失败");
// 失败时继续登录流程,不影响认证
}
}
}
registered it at:
private void PreConfigureOpenIddict(IConfiguration configuration, IWebHostEnvironment hostingEnvironment)
{
PreConfigure<OpenIddictBuilder>(builder =>
{
builder.AddValidation(options =>
{
options.AddAudiences("AuthServer");
options.UseLocalServer();
options.UseAspNetCore();
});
builder.AddServer(options =>
{
options.AddEventHandler<ProcessSignInContext>(builder =>
builder.UseInlineHandler(context =>
{
// Attach custom metadata to the configuration document.
//context.Metadata["custom_metadata"] = 42;
context.Logger.LogInformation("Processing sign-in event in inline handler for user {userId}.", context.Principal?.FindFirst(OpenIddictConstants.Claims.Subject)?.Value);
return default;
}));
});
});
PreConfigure<OpenIddictServerBuilder>(serverBuilder =>
{
serverBuilder.AddEventHandler(DailyPointsHandler.Descriptor);
serverBuilder.AddEventHandler(SignOutEventHandler.Descriptor);
serverBuilder.AddEventHandler<ProcessSignInContext>(builder =>
builder.UseInlineHandler(context =>
{
// Attach custom metadata to the configuration document.
//context.Metadata["custom_metadata"] = 42;
context.Logger.LogInformation("Processing sign-in event in inline handler for user {userId}.", context.Principal?.FindFirst(OpenIddictConstants.Claims.Subject)?.Value);
return default;
}));
});
}