Open Closed

Feature Management #6550


User avatar
0
oleksandra.nakonechniuk created

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&lt;List&lt;AssessmentTypeDto&gt;> GetListAssessmentTypesWithCheckedFeatures(List&lt;AssessmentType&gt; asmtypes)
{
    var results = _objectMapper.Map&lt;List&lt;AssessmentType&gt;, List&lt;AssessmentTypeDto&gt;>(asmtypes);
    var updatedResults = new List&lt;AssessmentTypeDto&gt;();

    foreach (var m in results)
    {
        var isEnableType = await _featureChecker.IsEnabledAsync(m.Code);

        if (isEnableType)
        {
            var movements = new List&lt;AssessmentMovementDto&gt;();

            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&lt;AssessmentMovementDto&gt;();
        }

        if (isEnableType)
        {
            updatedResults.Add(m);
        }
    }

    return updatedResults;
}

15 Answer(s)
  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    Hi,

    can you please share any logs?

  • User Avatar
    0
    oleksandra.nakonechniuk created

  • User Avatar
    0
    oleksandra.nakonechniuk created

    this what method get features return and next time it will be 200

  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    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,

  • User Avatar
    0
    oleksandra.nakonechniuk created

    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?

  • User Avatar
    0
    oleksandra.nakonechniuk created

    And is it ok that I have FeatureDefinitionProvider in the domain project

  • User Avatar
    0
    oleksandra.nakonechniuk created

    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&lt;_3MFeatureResource&gt;(name);
    }
    

    }

  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    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

  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    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

  • User Avatar
    0
    oleksandra.nakonechniuk created

    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.

  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    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;
    });
    
    
  • User Avatar
    0
    oleksandra.nakonechniuk created

    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.Task1[System.Collections.Generic.List1[_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(List1 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, ValueTask1 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

  • User Avatar
    0
    oleksandra.nakonechniuk created

    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.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 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.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 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.CastleAsyncAbpInterceptorAdapter1.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, ValueTask1 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'

  • User Avatar
    0
    oleksandra.nakonechniuk created

    Is it enough for stack trace. Or we need to add this code and we will have more information?

  • User Avatar
    0
    Anjali_Musmade created
    Support Team Support Team Member

    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.

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11