Open Closed

openiddict add extra property, the value can not save, #3836


User avatar
0
zangwanyu created
  • ABP Framework version: v6.0.0
  • UI type: Blazor
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): yes
  • Exception message and stack trace:
  • [12:18:25 DBG] PermissionStore.GetCacheItemAsync: pn:U,pk:94c36bd4-906c-396b-19fa-3a06ce4ddc17,n:OpenIddictPro.Application [12:18:25 DBG] Found in the cache: pn:U,pk:94c36bd4-906c-396b-19fa-3a06ce4ddc17,n:OpenIddictPro.Application [12:18:25 DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:admin,n:OpenIddictPro.Application [12:18:25 DBG] Found in the cache: pn:R,pk:admin,n:OpenIddictPro.Application [12:18:25 DBG] PermissionStore.GetCacheItemAsync: pn:C,pk:vSkysoft_BlazorServer,n:OpenIddictPro.Application [12:18:25 DBG] Found in the cache: pn:C,pk:vSkysoft_BlazorServer,n:OpenIddictPro.Application [12:18:25 INF] Executing ObjectResult, writing value of type 'Volo.Abp.OpenIddict.Applications.Dtos.ApplicationDto'. [12:18:25 INF] Executed action Volo.Abp.OpenIddict.ApplicationController.GetAsync (Volo.Abp.OpenIddict.Pro.HttpApi) in 42.6238ms [12:18:25 INF] Executed endpoint 'Volo.Abp.OpenIddict.ApplicationController.GetAsync (Volo.Abp.OpenIddict.Pro.HttpApi)' [12:18:25 INF] Request finished HTTP/1.1 GET https://localhost:44388/api/openiddict/applications/496c821d-cf08-a729-a0d7-3a06ce526930?api-version=1.0 - 0 - 200 - application/json;+charset=utf-8 47.6289ms [12:18:34 INF] Request starting HTTP/1.1 PUT https://localhost:44388/api/openiddict/applications/496c821d-cf08-a729-a0d7-3a06ce526930?api-version=1.0 application/json;+charset=utf-8 653 [12:18:34 INF] Executing endpoint 'Volo.Abp.OpenIddict.ApplicationController.UpdateAsync (Volo.Abp.OpenIddict.Pro.HttpApi)' [12:18:34 INF] Route matched with {controller = "Applications", area = "openiddictpro", action = "Update"}. Executing controller action with signature System.Threading.Tasks.Task`1[Volo.Abp.OpenIddict.Applications.Dtos.ApplicationDto] UpdateAsync(System.Guid, Volo.Abp.OpenIddict.Applications.Dtos.UpdateApplicationInput) on controller Volo.Abp.OpenIddict.ApplicationController (Volo.Abp.OpenIddict.Pro.HttpApi). [12:18:34 DBG] PermissionStore.GetCacheItemAsync: pn:U,pk:94c36bd4-906c-396b-19fa-3a06ce4ddc17,n:OpenIddictPro.Application.Update [12:18:34 DBG] Found in the cache: pn:U,pk:94c36bd4-906c-396b-19fa-3a06ce4ddc17,n:OpenIddictPro.Application.Update [12:18:34 DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:admin,n:OpenIddictPro.Application.Update [12:18:34 DBG] Found in the cache: pn:R,pk:admin,n:OpenIddictPro.Application.Update [12:18:34 DBG] PermissionStore.GetCacheItemAsync: pn:C,pk:vSkysoft_BlazorServer,n:OpenIddictPro.Application.Update [12:18:34 DBG] Found in the cache: pn:C,pk:vSkysoft_BlazorServer,n:OpenIddictPro.Application.Update [12:18:34 DBG] PermissionStore.GetCacheItemAsync: pn:U,pk:94c36bd4-906c-396b-19fa-3a06ce4ddc17,n:OpenIddictPro.Application [12:18:34 DBG] Found in the cache: pn:U,pk:94c36bd4-906c-396b-19fa-3a06ce4ddc17,n:OpenIddictPro.Application [12:18:34 DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:admin,n:OpenIddictPro.Application [12:18:34 DBG] Found in the cache: pn:R,pk:admin,n:OpenIddictPro.Application [12:18:34 DBG] PermissionStore.GetCacheItemAsync: pn:C,pk:vSkysoft_BlazorServer,n:OpenIddictPro.Application [12:18:34 DBG] Found in the cache: pn:C,pk:vSkysoft_BlazorServer,n:OpenIddictPro.Application [12:18:34 WRN] Savepoints are disabled because Multiple Active Result Sets (MARS) is enabled. If 'SaveChanges' fails, then the transaction cannot be automatically rolled back to a known clean state. Instead, the transaction should be rolled back by the application before retrying 'SaveChanges'. See https://go.microsoft.com/fwlink/?linkid=2149338 for more information. To identify the code which triggers this warning, call 'ConfigureWarnings(w => w.Throw(SqlServerEventId.SavepointsDisabledBecauseOfMARS))'. [12:18:34 DBG] Added 0 entity changes to the current audit log [12:18:34 DBG] Added 0 entity changes to the current audit log [12:18:34 INF] Executing ObjectResult, writing value of type 'Volo.Abp.OpenIddict.Applications.Dtos.ApplicationDto'. [12:18:34 INF] Executed action Volo.Abp.OpenIddict.ApplicationController.UpdateAsync (Volo.Abp.OpenIddict.Pro.HttpApi) in 402.5191ms [12:18:34 INF] Executed endpoint 'Volo.Abp.OpenIddict.ApplicationController.UpdateAsync (Volo.Abp.OpenIddict.Pro.HttpApi)' [12:18:34 DBG] Added 0 entity changes to the current audit log [12:18:34 DBG] Added 0 entity changes to the current audit log [12:18:34 DBG] Added 0 entity changes to the current audit log [12:18:34 DBG] Added 0 entity changes to the current audit log [12:18:34 INF] Request finished HTTP/1.1 PUT https://localhost:44388/api/openiddict/applications/496c821d-cf08-a729-a0d7-3a06ce526930?api-version=1.0 application/json;+charset=utf-8 653 - 200 - application/json;+charset=utf-8 670.3044ms
  • Steps to reproduce the issue:"
Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

8 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Please share the full steps to reproduce. Thanks.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    zangwanyu created

    @using Volo.Abp.OpenIddict.Pro.Blazor.Pages

    @inherits ApplicationManagement

    @{ base.BuildRenderTree(__builder); }

    @if (HasUpdatePermission){

    <DxPopup HeaderText="@L["Application"]" @bind-Visible="ApplicationPopup" Context="DxPopupContext" @ref="dxPopup"> <BodyContentTemplate>

        &lt;DxFormLayout&gt;
            
            &lt;DxFormLayoutItem ColSpanMd=&quot;12&quot; Context=&quot;item&quot;&gt;
                &lt;DxComboBox Data=&quot;organizationUnitDtoList&quot;
                            FilteringMode=&quot;DataGridFilteringMode.Contains&quot;
                            TextFieldName=&quot;DisplayName&quot;
                            ValueFieldName=&quot;Id&quot;
                            ClearButtonDisplayMode=&quot;DataEditorClearButtonDisplayMode.Auto&quot;
                            @bind-Value=&quot;@(EditingEntity.ExtraProperties[&quot;OrganizationUnitId&quot;])&quot;&gt;
                    @L["OrganizationUnit"]
                &lt;/DxComboBox&gt;
            &lt;/DxFormLayoutItem&gt;
                        
            &lt;DxFormLayoutItem ColSpanMd=&quot;12&quot; Context=&quot;item&quot;&gt;
                &lt;DxCheckBox @bind-Checked=&quot;@(NeedVAuthority)&quot;&gt;
                    @L["NeedVAuthority"]
                &lt;/DxCheckBox&gt;
            &lt;/DxFormLayoutItem&gt;
    
            &lt;DxFormLayoutItem ColSpanMd=&quot;12&quot;&gt;
                &lt;div class=&quot;right-align&quot;&gt;
                    &lt;DxButton RenderStyle=&quot;ButtonRenderStyle.Primary&quot; Text=&quot;@L[&quot;Cancel&quot;]&quot; Click=&quot;()=&gt;ApplicationPopup=false" />
    

    <DxButton RenderStyle="ButtonRenderStyle.Secondary" Text="@L["Confirm"]" Click="ConfirmChange" />

                &lt;/div&gt;
            &lt;/DxFormLayoutItem&gt;
    
        &lt;/DxFormLayout&gt;
    
    &lt;/BodyContentTemplate&gt;
    

    </DxPopup> }

    using DevExpress.Blazor; using Microsoft.AspNetCore.Components; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions; using Volo.Abp.BlazoriseUI; using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectMapping; using Volo.Abp.OpenIddict.Applications; using Volo.Abp.OpenIddict.Applications.Dtos; using Volo.Abp.OpenIddict.Pro.Blazor.Pages;

    namespace aa.IdentityService.Blazor.Pages.IdentityServer {

    [ExposeServices(typeof(ApplicationManagement))]

    [Dependency(ReplaceServices = true)]

    public partial class CustomApplicationManagement
    {
        [Inject] IOrganizationUnitAppService OrganizationUnitAppService { get; set; }
    
        bool ApplicationPopup;
        DxPopup dxPopup;
    
        List&lt;OrganizationUnitWithDetailsDto&gt; organizationUnitDtoList;
    
        protected override async Task OnInitializedAsync()
        {
            await base.OnInitializedAsync();
            var organizationUnitResult = await OrganizationUnitAppService.GetListAllAsync();
            organizationUnitDtoList = organizationUnitResult.Items.Where(u => u.ParentId == null).ToList();
        }
    
        protected async override Task OpenCreateModalAsync()
        {
            Scopes = (await ScopeAppService.GetAllScopesAsync()).ToDictionary(x => x.Name, x => false);
            CreateInput = new ApplicationModalView();
            CreateInput.ExtraProperties["NeedVAuthority"] = false;
            try
            {
                if (CreateValidationsRef != null)
                {
                    await CreateValidationsRef.ClearAll();
                }
    
                await CheckCreatePolicyAsync();
    
                NewEntity = new CreateApplicationInput();
    
                // Mapper will not notify Blazor that binded values are changed
                // so we need to notify it manually by calling StateHasChanged
                await InvokeAsync(async () =>
                {
                    StateHasChanged();
                    if (CreateModal != null)
                    {
                        await CreateModal.Show();
                    }
    
                });
            }
            catch (Exception ex)
            {
                await HandleErrorAsync(ex);
            }
        }
    
    
        async Task OpenApplicationAsync(ApplicationDto entity)
        {
            if (dxPopup is not null)
            {
                ApplicationPopup = true;
    
                var entityDto = await AppService.GetAsync(entity.Id);
    
                EditingEntityId = entity.Id;
                EditingEntity = MapToEditingEntity(entityDto);
                EditingEntity.ExtraProperties["NeedVAuthority"] = false;
                EditingEntity.ExtraProperties["OrganizationUnitId"] = "";
    
                //EditingClientModelView = ObjectMapper.Map&lt;UpdateClientDto, UpdateClientModelView&gt;(EditingEntity);
                await InvokeAsync(StateHasChanged);
    
                await dxPopup.ShowAsync();
            }
        }
    
    
    
        protected async override Task OpenEditModalAsync(ApplicationDto entity)
        {
            await base.OpenEditModalAsync(entity);
            CreateInput.ClientUri = entity.ClientUri;
            CreateInput.LogoUri = entity.LogoUri;
            Scopes = (await ScopeAppService.GetAllScopesAsync()).ToDictionary(x => x.Name, x => EditingEntity.Scopes.Any(s => s == x.Name));
            await InvokeAsync(StateHasChanged);
        }
    
        protected override UpdateApplicationInput MapToEditingEntity(ApplicationDto entityDto)
        {
            UpdateInput = ObjectMapper.Map&lt;ApplicationDto, ApplicationModalView&gt;(entityDto);
            return base.MapToEditingEntity(entityDto); ;
        }
    
        protected override Task OnUpdatingEntityAsync()
        {
            UpdateInput.Scopes = Scopes.Where(x => x.Value).Select(x => x.Key).ToHashSet();
            UpdateInput.LogoUri = CreateInput.LogoUri;
            UpdateInput.ClientUri = CreateInput.ClientUri;
            EditingEntity = ObjectMapper.Map&lt;ApplicationModalView, UpdateApplicationInput&gt;(UpdateInput);
            return base.OnUpdatingEntityAsync();
        }
    
        protected override ValueTask SetEntityActionsAsync()
        {
            EntityActions
                .Get&lt;ApplicationManagement&gt;()
                .Add(
                    new EntityAction
                    {
                        Text = L["Application"],
                        Visible = (data) => HasUpdatePermission,
                        Clicked = async (data) => await OpenApplicationAsync(data.As&lt;ApplicationDto&gt;())
                    });
    
            return base.SetEntityActionsAsync();
        }
    
        bool NeedVAuthority
        {
            get => (bool)EditingEntity.ExtraProperties["NeedVAuthority"];
            set => EditingEntity.ExtraProperties["NeedVAuthority"] = value;
        }
    

    async Task ConfirmChange()

    {

    await AppService.UpdateAsync(EditingEntityId, EditingEntity);

    ApplicationPopup = false;

    }

    }
    

    }

    Invoke method ConfirmChange()

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Please try to format your code. It is unreadable. Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    zangwanyu created

    CustomApplicationManagment.razor

    @using Volo.Abp.OpenIddict.Pro.Blazor.Pages @inherits ApplicationManagement

    @{ base.BuildRenderTree(__builder); }

    @if (HasUpdatePermission){

    <DxPopup HeaderText="@L["Application"]" @bind-Visible="ApplicationPopup" Context="DxPopupContext" @ref="dxPopup"> <BodyContentTemplate>

        &lt;DxFormLayout&gt;
            
            &lt;DxFormLayoutItem ColSpanMd=&quot;12&quot; Context=&quot;item&quot;&gt;
                &lt;DxComboBox Data=&quot;organizationUnitDtoList&quot;
                            FilteringMode=&quot;DataGridFilteringMode.Contains&quot;
                            TextFieldName=&quot;DisplayName&quot;
                            ValueFieldName=&quot;Id&quot;
                            ClearButtonDisplayMode=&quot;DataEditorClearButtonDisplayMode.Auto&quot;
                            @bind-Value=&quot;@(EditingEntity.ExtraProperties[&quot;OrganizationUnitId&quot;])&quot;&gt;
                    @L["OrganizationUnit"]
                &lt;/DxComboBox&gt;
            &lt;/DxFormLayoutItem&gt;
                        
            &lt;DxFormLayoutItem ColSpanMd=&quot;12&quot; Context=&quot;item&quot;&gt;
                &lt;DxCheckBox @bind-Checked=&quot;@(NeedVAuthority)&quot;&gt;
                    @L["NeedVAuthority"]
                &lt;/DxCheckBox&gt;
            &lt;/DxFormLayoutItem&gt;
    
            &lt;DxFormLayoutItem ColSpanMd=&quot;12&quot;&gt;
                &lt;div class=&quot;right-align&quot;&gt;
                    &lt;DxButton RenderStyle=&quot;ButtonRenderStyle.Primary&quot; Text=&quot;@L[&quot;Cancel&quot;]&quot; Click=&quot;()=&gt;ApplicationPopup=false" />
                    &lt;DxButton RenderStyle=&quot;ButtonRenderStyle.Secondary&quot; Text=&quot;@L[&quot;Confirm&quot;]&quot; Click=&quot;ConfirmChange&quot; /&gt;
                &lt;/div&gt;
            &lt;/DxFormLayoutItem&gt;
    
        &lt;/DxFormLayout&gt;
    
    &lt;/BodyContentTemplate&gt;
    

    </DxPopup> }

    CustomApplicationManagement.razor.cs

    using DevExpress.Blazor;
    using Microsoft.AspNetCore.Components;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;
    using System.Threading.Tasks;
    using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions;
    using Volo.Abp.BlazoriseUI;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.Identity;
    using Volo.Abp.ObjectExtending;
    using Volo.Abp.ObjectMapping;
    using Volo.Abp.OpenIddict.Applications;
    using Volo.Abp.OpenIddict.Applications.Dtos;
    using Volo.Abp.OpenIddict.Pro.Blazor.Pages;
    
    namespace MySoft.IdentityService.Blazor.Pages.IdentityServer
    {
    
    [ExposeServices(typeof(ApplicationManagement))]
    [Dependency(ReplaceServices = true)]
    public partial class CustomApplicationManagement
    {
        [Inject] IOrganizationUnitAppService OrganizationUnitAppService { get; set; }
    
        bool ApplicationPopup;
        DxPopup dxPopup;
    
        List<OrganizationUnitWithDetailsDto> organizationUnitDtoList;
    
        protected override async Task OnInitializedAsync()
        {
            await base.OnInitializedAsync();
            var organizationUnitResult = await OrganizationUnitAppService.GetListAllAsync();
            organizationUnitDtoList = organizationUnitResult.Items.Where(u => u.ParentId == null).ToList();
        }
    
        protected async override Task OpenCreateModalAsync()
        {
            Scopes = (await ScopeAppService.GetAllScopesAsync()).ToDictionary(x => x.Name, x => false);
            CreateInput = new ApplicationModalView();
            CreateInput.ExtraProperties["NeedVAuthority"] = false;
            try
            {
                if (CreateValidationsRef != null)
                {
                    await CreateValidationsRef.ClearAll();
                }
    
                await CheckCreatePolicyAsync();
    
                NewEntity = new CreateApplicationInput();
    
                // Mapper will not notify Blazor that binded values are changed
                // so we need to notify it manually by calling StateHasChanged
                await InvokeAsync(async () =>
                {
                    StateHasChanged();
                    if (CreateModal != null)
                    {
                        await CreateModal.Show();
                    }
    
                });
            }
            catch (Exception ex)
            {
                await HandleErrorAsync(ex);
            }
        }
    
    
        async Task OpenApplicationAsync(ApplicationDto entity)
        {
            if (dxPopup is not null)
            {
                ApplicationPopup = true;
    
                var entityDto = await AppService.GetAsync(entity.Id);
    
                EditingEntityId = entity.Id;
                EditingEntity = MapToEditingEntity(entityDto);
                EditingEntity.ExtraProperties["NeedVAuthority"] = false;
                EditingEntity.ExtraProperties["OrganizationUnitId"] = "";
    
                //EditingClientModelView = ObjectMapper.Map<UpdateClientDto, UpdateClientModelView>(EditingEntity);
                await InvokeAsync(StateHasChanged);
    
                await dxPopup.ShowAsync();
            }
        }
    
    
    
        protected async override Task OpenEditModalAsync(ApplicationDto entity)
        {
            await base.OpenEditModalAsync(entity);
            CreateInput.ClientUri = entity.ClientUri;
            CreateInput.LogoUri = entity.LogoUri;
            Scopes = (await ScopeAppService.GetAllScopesAsync()).ToDictionary(x => x.Name, x => EditingEntity.Scopes.Any(s => s == x.Name));
            await InvokeAsync(StateHasChanged);
        }
    
        protected override UpdateApplicationInput MapToEditingEntity(ApplicationDto entityDto)
        {
            UpdateInput = ObjectMapper.Map<ApplicationDto, ApplicationModalView>(entityDto);
            return base.MapToEditingEntity(entityDto); ;
        }
    
        protected override Task OnUpdatingEntityAsync()
        {
            UpdateInput.Scopes = Scopes.Where(x => x.Value).Select(x => x.Key).ToHashSet();
            UpdateInput.LogoUri = CreateInput.LogoUri;
            UpdateInput.ClientUri = CreateInput.ClientUri;
            EditingEntity = ObjectMapper.Map<ApplicationModalView, UpdateApplicationInput>(UpdateInput);
            return base.OnUpdatingEntityAsync();
        }
    
        protected override ValueTask SetEntityActionsAsync()
        {
            EntityActions
                .Get<ApplicationManagement>()
                .Add(
                    new EntityAction
                    {
                        Text = L["Application"],
                        Visible = (data) => HasUpdatePermission,
                        Clicked = async (data) => await OpenApplicationAsync(data.As<ApplicationDto>())
                    });
    
            return base.SetEntityActionsAsync();
        }
    
        bool NeedVAuthority
        {
            get => (bool)EditingEntity.ExtraProperties["NeedVAuthority"];
            set => EditingEntity.ExtraProperties["NeedVAuthority"] = value;
        }
        async Task ConfirmChange()
        {
            await AppService.UpdateAsync(EditingEntityId, EditingEntity);
            ApplicationPopup = false;
        }
      }
    }
    

    the AppService.UpdateAsync method can't save extra properties values

    var entityDto = await AppService.GetAsync(entity.Id); The GetAsync method also can't get extra properties values

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    ok, I will check this asap.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you create a new template project and reproduce the problem? (You can call application in unit test)

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    zangwanyu created

    yes

    using Volo.Abp.ObjectExtending;
    using Volo.Abp.Threading;
    
    namespace TestApp;
    
    public static class TestAppModuleExtensionConfigurator
    {
        private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
    
        public static void Configure()
        {
            OneTimeRunner.Run(() =>
            {
                ConfigureExistingProperties();
                ConfigureExtraProperties();
            });
        }
    
        private static void ConfigureExistingProperties()
        {
            /* You can change max lengths for properties of the
             * entities defined in the modules used by your application.
             *
             * Example: Change user and role name max lengths
    
               IdentityUserConsts.MaxNameLength = 99;
               IdentityRoleConsts.MaxNameLength = 99;
    
             * Notice: It is not suggested to change property lengths
             * unless you really need it. Go with the standard values wherever possible.
             *
             * If you are using EF Core, you will need to run the add-migration command after your changes.
             */
        }
    
        private static void ConfigureExtraProperties()
        {
            /* You can configure extra properties for the
             * entities defined in the modules used by your application.
             *
             * This class can be used to define these extra properties
             * with a high level, easy to use API.
             *
             * Example: Add a new property to the user entity of the identity module
    
               ObjectExtensionManager.Instance.Modules()
                  .ConfigureIdentity(identity =>
                  {
                      identity.ConfigureUser(user =>
                      {
                          user.AddOrUpdateProperty<string>( //property type: string
                              "SocialSecurityNumber", //property name
                              property =>
                              {
                                  //validation rules
                                  property.Attributes.Add(new RequiredAttribute());
                                  property.Attributes.Add(new StringLengthAttribute(64) {MinimumLength = 4});
    
                                  //...other configurations for this property
                              }
                          );
                      });
                  });
    
             * See the documentation for more:
             * https://docs.abp.io/en/abp/latest/Module-Entity-Extensions
             */
    
            ObjectExtensionManager.Instance.Modules()
                  .ConfigureOpenIddict(openid =>
                  {
                      openid.ConfigureApplication(app =>
                      {
                          app.AddOrUpdateProperty<string>("Description");                        
                      });
                  });
        }
    }
    
    
    using Volo.Abp.ObjectExtending;
    using Volo.Abp.OpenIddict.Applications;
    using Volo.Abp.Threading;
    
    namespace TestApp.EntityFrameworkCore;
    
    public static class TestAppEfCoreEntityExtensionMappings
    {
        private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
    
        public static void Configure()
        {
            TestAppGlobalFeatureConfigurator.Configure();
            TestAppModuleExtensionConfigurator.Configure();
    
            OneTimeRunner.Run(() =>
            {
                /* You can configure extra properties for the
                 * entities defined in the modules used by your application.
                 *
                 * This class can be used to map these extra properties to table fields in the database.
                 *
                 * USE THIS CLASS ONLY TO CONFIGURE EF CORE RELATED MAPPING.
                 * USE TestAppModuleExtensionConfigurator CLASS (in the Domain.Shared project)
                 * FOR A HIGH LEVEL API TO DEFINE EXTRA PROPERTIES TO ENTITIES OF THE USED MODULES
                 *
                 * Example: Map a property to a table field:
    
                     ObjectExtensionManager.Instance
                         .MapEfCoreProperty<IdentityUser, string>(
                             "MyProperty",
                             (entityBuilder, propertyBuilder) =>
                             {
                                 propertyBuilder.HasMaxLength(128);
                             }
                         );
    
                 * See the documentation for more:
                 * https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Extending-Entities
                 */
    
                ObjectExtensionManager.Instance
                    .MapEfCoreProperty<OpenIddictApplication, string>("Description");
            });
        }
    }
    
    

    The test case code is as follows

    using Shouldly;
    using System.Threading.Tasks;
    using Volo.Abp.OpenIddict.Applications;
    using Volo.Abp.OpenIddict.Applications.Dtos;
    using Xunit;
    
    namespace TestApp.Samples;
    
    /* This is just an example test class.
     * Normally, you don't test code of the modules you are using
     * (like IIdentityUserAppService here).
     * Only test your own application services.
     */
    public class SampleAppServiceTests : TestAppApplicationTestBase
    {
        private readonly IApplicationAppService _applicationAppService;
    
        public SampleAppServiceTests()
        {
            _applicationAppService = GetRequiredService<IApplicationAppService>();
        }
    
        [Fact]
        public async Task Should_Set_Description_Of_An_Application()
        {
            await WithUnitOfWorkAsync(async () =>
            {
                var app = new CreateApplicationInput()
                {
                    ClientId = "test",
                    DisplayName = "test"
                };
    
                app.ExtraProperties["Description"] = "Description1";
    
                await _applicationAppService.CreateAsync(app);
            });
            var list = await _applicationAppService.GetListAsync(new()
            {
                MaxResultCount = 1
            });
    
            // list.Items[0].ExtraProperties["Description"].ShouldBe("Description1");
    
            var app = await _applicationAppService.GetAsync(list.Items[0].Id);
    
            app.ExtraProperties["Description"].ShouldBe("Description1");
    
            
        }
    }
    
    

    The test failed as follows

     TestApp.Samples.SampleAppServiceTests.Should_Set_Description_Of_An_Application
       源: SampleAppServiceTests.cs 行 33
       持续时间: 4.3 秒
    
      消息: 
    Shouldly.ShouldAssertException : app.ExtraProperties["Description"]
        should be
    "Description1"
        but was
    null
    
      堆栈跟踪: 
    SampleAppServiceTests.Should_Set_Description_Of_An_Application() 行 56
    ExceptionDispatchInfo.Throw()
    TaskAwaiter.ThrowForNonSuccess(Task task)
    TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    TaskAwaiter.GetResult()
    --- End of stack trace from previous location ---
    ExceptionDispatchInfo.Throw()
    TaskAwaiter.ThrowForNonSuccess(Task task)
    TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    TaskAwaiter.GetResult()
    ExceptionDispatchInfo.Throw()
    TaskAwaiter.ThrowForNonSuccess(Task task)
    TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    TaskAwaiter.GetResult()
    
    

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    This is an unknown problem, We will release a new 6.0 patch version.

    https://github.com/abpframework/abp/pull/14306

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
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 September 16, 2026, 14:50
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.