Hello. I created FeatureDefinitionProvider in the domain layer. Is it ok? because I need to take some data from the database. Is it possible to do like this? And then I use the feature checker as You provide in the documentation. Can the name of the feature be with white space?
I am asking because when I created these features and load to prod, they were working correctly. But after several deploys, they fell. The method where I use the feature checker works every second time. I mean one time it returns a response next time it returns 500 HTTP error. And say that can't found feature the first in the list.
My using of feature checker :
public async Task<List<AssessmentTypeDto?>> GetMovementsTestFeatures() { var mvmTypes = await _asmTypeRepository.GetAssessmentTypes(AssessmentTypeNames.Movement); return await GetListAssessmentTypesWithCheckedFeatures(mvmTypes); }
private async Task<List<AssessmentTypeDto>> GetListAssessmentTypesWithCheckedFeatures(List<AssessmentType> asmtypes)
{
var results = _objectMapper.Map<List<AssessmentType>, List<AssessmentTypeDto>>(asmtypes);
var updatedResults = new List<AssessmentTypeDto>();
foreach (var m in results)
{
var isEnableType = await _featureChecker.IsEnabledAsync(m.Code);
if (isEnableType)
{
var movements = new List<AssessmentMovementDto>();
foreach (var x in m.Movements)
{
var isEnabled = await _featureChecker.IsEnabledAsync(x.Code);
if (isEnabled)
{
movements.Add(x);
}
}
m.Movements = movements.OrderBy(x => x.DisplayOrder).ToList();
}
else
{
m.Movements = new List<AssessmentMovementDto>();
}
if (isEnableType)
{
updatedResults.Add(m);
}
}
return updatedResults;
}
15 Answer(s)
-
0
Hi,
can you please share any logs?
-
0
-
0
this what method get features return and next time it will be 200
-
0
Hi,
I think the issue is in your code shared above. Try to optimize it.
I am not sure but can you please try with this code
private async Task<List<AssessmentTypeDto>> GetListAssessmentTypesWithCheckedFeatures(List<AssessmentType> asmtypes) { var results = _objectMapper.Map<List<AssessmentType>, List<AssessmentTypeDto>>(asmtypes); var updatedResults = new List<AssessmentTypeDto>(); foreach (var m in results) { var isEnableType = await _featureChecker.IsEnabledAsync(m.Code); if (isEnableType) { var movements = m.Movements.Where(x => await _featureChecker.IsEnabledAsync(x.Code)).OrderBy(x => x.DisplayOrder).ToList(); m.Movements = movements; updatedResults.Add(m); } else { m.Movements = new List<AssessmentMovementDto>(); } } return updatedResults; }
thanks,
-
0
I will try. But what about get features it fell down two. And can You answer me can feature has a name with white spaces?
-
0
And is it ok that I have FeatureDefinitionProvider in the domain project
-
0
My public class AssessmentFeatureDefinitionProvider : FeatureDefinitionProvider { private readonly IAssessmentTypeRepository _assessmentTypeRepository; private const string FeatureNameForSingleMovements = "Tasks"; private const string FeatureNameForProtocols = "Protocols";
public AssessmentFeatureDefinitionProvider(IAssessmentTypeRepository assessmentTypeRepository) { _assessmentTypeRepository = assessmentTypeRepository; } public override async void Define(IFeatureDefinitionContext context) { var tasksGroup = context.AddGroup(FeatureNameForSingleMovements); var protocolGroup = context.AddGroup(FeatureNameForProtocols); await DefineFeaturesForAssessmentType(tasksGroup, AssessmentTypeNames.Movement); await DefineFeaturesForAssessmentType(protocolGroup, AssessmentTypeNames.Protocol); } private async Task DefineFeaturesForAssessmentType(FeatureGroupDefinition contextGroup, AssessmentTypeNames assessmentTypeName) { var assessmentTypes = await _assessmentTypeRepository.GetAssessmentTypes(assessmentTypeName); foreach (var assessmentType in assessmentTypes) { var feature = contextGroup.AddFeature(assessmentType.Code, defaultValue: "true", displayName: L($"DisplayName:AssessmentType.{assessmentType.Code}")); var movements = assessmentType.AssessmentTypeMovements.Select(x => x.AssessmentMovement).ToList(); foreach (var movement in movements) { feature.CreateChild(movement.Code, defaultValue: "true", displayName: L($"DisplayName:AssessmentMovement.{movement.Code}")); } } } private static LocalizableString L(string name) { return LocalizableString.Create<_3MFeatureResource>(name); }
}
-
0
And is it ok that I have FeatureDefinitionProvider in the domain project
You may have but its better to have in
Application.Contracts
check here in documentation https://docs.abp.io/en/abp/latest/Features#featuredefinitionprovider -
0
I will try. But what about get features it fell down two.
And can You answer me can feature has a name with white spaces?No, feature must has some name it is not possible with white space you may check here https://docs.abp.io/en/abp/latest/Features#other-feature-properties
-
0
This part x => await _featureChecker.IsEnabledAsync(x.Code) will not work it needs WhenAll but this works with repository and I had some problems with WhenAll and asynchronous calls to db.
-
0
Hi
can you configure this in your module and then share the logs it will be helpful if the strack trace is there
Configure<AbpExceptionHandlingOptions>(options => { options.SendExceptionsDetailsToClients = true; options.SendStackTraceToClients = true; });
-
0
I can send You stackTrace [13:39:47 INF] Request starting HTTP/1.1 GET http://api-dev.3motionai.com/api/app/assessment-types/movements - - [13:39:47 INF] Sentry trace header is null. Creating new Sentry Propagation Context. [13:39:47 INF] Started transaction with span ID '3407bb84c47c4acd' and trace ID '18271856ff714539a8b97737c3b2da46'. [13:39:47 INF] Executing endpoint '_3M.AssessmentTypes.AssessmentTypesAppService.GetMovements (_3M.Application)' [13:39:47 INF] Route matched with {action = "GetMovements", controller = "AssessmentTypes", area = "", page = ""}. Executing controller action with signature System.Threading.Tasks.Task
1[System.Collections.Generic.List
1[_3M.AssessmentTypes.AssessmentTypeDto]] GetMovements() on controller _3M.AssessmentTypes.AssessmentTypesAppService (_3M.Application). [13:39:48 ERR] ---------- RemoteServiceErrorInfo ---------- { "code": null, "message": "An internal error occurred during your request!", "details": null, "data": {}, "validationErrors": null }[13:39:48 ERR] Undefined feature: Sports Volo.Abp.AbpException: Undefined feature: Sports at Volo.Abp.Features.FeatureDefinitionManager.GetAsync(String name) at Volo.Abp.Features.FeatureChecker.GetOrNullAsync(String name) at Volo.Abp.Features.FeatureCheckerBase.IsEnabledAsync(String name) at _3M.AssessmentTypes.AssessmentTypesAppService.GetListAssessmentTypesWithCheckedFeatures(List
1 asmtypes) in /azp/_work/1/s/src/_3M.Application/AssessmentTypes/AssessmentTypesAppService.cs:line 80 at _3M.AssessmentTypes.AssessmentTypesAppService.GetMovements() in /azp/_work/1/s/src/_3M.Application/AssessmentTypes/AssessmentTypesAppService.cs:line 58 at lambda_method2576(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.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask
1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) [13:39:48 INF] Executing ObjectResult, writing value of type 'Volo.Abp.Http.RemoteServiceErrorResponse'. [13:39:48 INF] Executed action _3M.AssessmentTypes.AssessmentTypesAppService.GetMovements (_3M.Application) in 450.3411ms [13:39:48 INF] Executed endpoint '_3M.AssessmentTypes.AssessmentTypesAppService.GetMovements (_3M.Application)' [13:39:48 INF] Enve -
0
13:40:27 INF] Executed endpoint 'Health checks' [13:40:27 INF] Event dropped by processor CustomSentryProcessor [13:40:27 INF] Request finished HTTP/1.1 GET http://10.244.6.75:80/health-status - - - 200 - application/json 4.1482ms [13:40:27 INF] Executed endpoint 'Health checks' [13:40:27 INF] Event dropped by processor CustomSentryProcessor [13:40:27 INF] Request finished HTTP/1.1 GET http://10.244.6.75:80/health-status - - - 200 - application/json 3.0396ms [13:40:27 ERR] ---------- RemoteServiceErrorInfo ---------- { "code": null, "message": "An internal error occurred during your request!", "details": null, "data": {}, "validationErrors": null }
[13:40:27 ERR] Undefined feature: risk Volo.Abp.AbpException: Undefined feature: risk at Volo.Abp.Features.FeatureDefinitionManager.GetAsync(String name) at Volo.Abp.FeatureManagement.FeatureManager.GetOrNullInternalAsync(String name, String providerName, String providerKey, Boolean fallback) at Volo.Abp.FeatureManagement.FeatureManager.GetOrNullWithProviderAsync(String name, String providerName, String providerKey, Boolean fallback) at Volo.Abp.FeatureManagement.FeatureAppService.GetAsync(String providerName, String providerKey) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue
1.ProceedAsync() at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter
1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue
1.ProceedAsync() at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func
3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope) at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter
1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue
1.ProceedAsync() at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func
3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter
1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at lambda_method3149(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.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask
1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) [13:40:27 INF] Executing ObjectResult, writing value of type 'Volo.Abp.Http.RemoteServiceErrorResponse'. [13:40:27 INF] Executed action Volo.Abp.FeatureManagement.FeaturesController.GetAsync (Volo.Abp.FeatureManagement.HttpApi) in 251.6018ms [13:40:27 INF] Executed endpoint 'Volo.Abp.FeatureManagement.FeaturesController.GetAsync (Volo.Abp.FeatureManagement.HttpApi)' [13:40:27 INF] Envelope queued up: 'd86a37c4329848568ba1fa8efc199355' [13:40:27 INF] Request finished HTTP/1.1 GET http://api-dev.3motionai.com/api/feature-management/features?providerName=T - - - 500 - application/json;+charset=utf-8 274.8530ms [13:40:27 INF] Envelope 'd86a37c4329848568ba1fa8efc199355' successfully sent. [13:40:34 INF] Start processing HTTP request GET http://3m-backend-api-webhost-dev2-55cd8c9cd4-qkxzs/health-status [13:40:34 INF] Sending HTTP request GET http://3m-backend-api-webhost-dev2-55cd8c9cd4-qkxzs/health-status [13:40:34 INF] Request starting HTTP/1.1 GET http://3m-backend-api-webhost-dev2-55cd8c9cd4-qkxzs/health-status - - [13:40:34 INF] Started transaction with span ID 'f1cd941c0dff465c' and trace ID '86a44028d26f496a91756b61b7026d02'. [13:40:34 INF] Executing endpoint 'Health checks' [13:40:34 INF] Executed endpoint 'Health checks' [13:40:34 INF] Received HTTP response headers after 3.8044ms - 200 [13:40:34 INF] End processing HTTP request after 3.9389ms - 200 [13:40:34 INF] Event dropped by processor CustomSentryProcessor [13:40:34 INF] Request finished HTTP/1.1 GET http://3m-backend-api-webhost-dev2-55cd8c9cd4-qkxzs/health-status - - - 200 - application/json 3.7909ms [13:40:42 INF] Request starting HTTP/1.1 GET http://10.244.6.75:80/health-status - - [13:40:42 INF] Request starting HTTP/1.1 GET http://10.244.6.75:80/health-status - - [13:40:42 INF] Sentry trace header is null. Creating new Sentry Propagation Context. [13:40:42 INF] Sentry trace header is null. Creating new Sentry Propagation Context. [13:40:42 INF] Started transaction with span ID 'e3d7716683cd4290' and trace ID '46a9a0a8ae604a9fa92fa0bda97e34b8'. [13:40:42 INF] Started transaction with span ID '57415cff88434c49' and trace ID '92d5b63d8cbe40d79d0872310c55d61e'. [13:40:42 INF] Executing endpoint 'Health checks' -
0
Is it enough for stack trace. Or we need to add this code and we will have more information?
-
0
Hi
public override async void Define(IFeatureDefinitionContext context) { var tasksGroup = context.AddGroup(FeatureNameForSingleMovements); var protocolGroup = context.AddGroup(FeatureNameForProtocols); await DefineFeaturesForAssessmentType(tasksGroup, AssessmentTypeNames.Movement); await DefineFeaturesForAssessmentType(protocolGroup, AssessmentTypeNames.Protocol); }
this method is not awaited so the feature are getting undefined
can you try using AsyncHelper To call your async method and run them in sync.
It would be good to define feature as a concrete and not from database.