Activities of "granade"

Environment

  • ABP Studio Version: 2.1.9
  • ABP Framework Version: 10.0.2
  • Project Type: Blazor Server
  • Mapping Library: Mapperly (migrated from AutoMapper using official migration guide)

Summary

When using ABP Studio to regenerate an entity in a project that was migrated from AutoMapper to Mapperly (following https://abp.io/docs/10.0/release-info/migration-guides/AutoMapper-To-Mapperly), the code generator appends duplicate mapper classes to the bottom of ApplicationMappers.cs instead of detecting and updating the existing Mapperly mapper definitions.

This causes the Mapperly source generator to crash, which cascades into dozens of compilation errors.

Steps to Reproduce

  1. Start with an ABP project that originally used AutoMapper (e.g., created with ABP Suite pre-10.0)
  2. Migrate to Mapperly following the official migration guide linked above
  3. Generate an entity (e.g., Product) with all options enabled — verify the project compiles
  4. Open the same entity in ABP Studio and regenerate it (even a minor change like unchecking Excel Export)
  5. Build the solution

What Happens

ABP Studio appends new mapper classes at the bottom of [ProjectName]ApplicationMappers.cs, even though Mapperly mappers for the same entity already exist earlier in the file. For example, the file ends up with both:

// Original (already existed, ~line 50)
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class ProductToProductDtoMapper : MapperBase<Product, ProductDto>
{
    public override partial ProductDto Map(Product source);
    public override partial void Map(Product source, ProductDto destination);
}

// Duplicate appended by ABP Studio (~line 200)
[Mapper]
public partial class ProductToProductDtoMappers : MapperBase<Product, ProductDto>
{
    public override partial ProductDto Map(Product source);
    public override partial void Map(Product source, ProductDto destination);
}

Note: some duplicates use a slightly different class name (trailing "s"), while others use the exact same class name, producing different error types.

This causes the Mapperly source generator to fail entirely with:

CS8785: Generator 'MapperGenerator' failed to generate source. Exception was of type 'InvalidOperationException' with message 'Sequence contains more than one element'

Because the source generator crashes, none of the ~100 mapper classes in the file receive their generated implementations, producing widespread CS8795 errors ("Partial method must have an implementation part because it has accessibility modifiers").

Additional Issue (same regeneration action)

When unchecking features like "Create user interface" and regenerating, ABP Studio correctly removes those methods from the base interface (e.g., IProductsAppService.cs). However, it does not update or warn about .Extended files that override or call the removed methods, causing additional CS0115 and CS1061 errors.

Expected Behavior

  1. ABP Studio should detect existing Mapperly mapper classes and update them in-place (or skip if unchanged), not append duplicates
  2. When removing methods from the base interface/service, ABP Studio should either update .Extended files or warn the developer about broken references

Suspected Root Cause

I believe ABP Studio's code generator may be looking for AutoMapper-style CreateMap<>() calls in a Profile class to determine whether mappers exist. In a migrated project, those calls have been replaced by Mapperly MapperBase<> classes, which the generator doesn't recognize — so it treats the entity as having no mappers and generates new ones.

Projects created fresh with ABP 10.0+ (where Mapperly is the default) likely don't have this issue because the generator was designed to work with the mapper format it created.

Workaround

Manually revert ApplicationMappers.cs from source control to remove the appended duplicates, then manually fix any .Extended files referencing removed methods.

Environment

Template: app ABP Studio Version: 2.1.8 (fresh solution) UI Framework: blazor-server Theme: leptonx Database Provider: ef **Database Management System: **sqlserver **Multi-Tenancy: **Yes

Steps to reproduce the issue
  1. Create a new ABP solution using ABP Studio 2.1.8
  2. Open ABP Suite and create a "Book" entity with default options, generate successfully
  3. Create an "Author" entity with a required navigation property to Book, generate successfully
  4. Re-open the Author entity in ABP Suite
  5. Delete the Book navigation property from Author
  6. Click "Save and generate"
  7. Generation fails with "error occurred on DB migration step"
  8. Inspect MenuContributor.cs — file is corrupted with invalid syntax
Exception message and full stack trace

ABP Suite reports: "error occurred on DB migration step" After generation, AbpSolution1MenuContributor.cs contains invalid C# syntax: context.Menu.AddItem(new ApplicationMenuItem(AbpSolution1Menus.Books, l["Menu:Books"], url: "/books", icon: "fa fa-file-alt", requiredPermissionName: AbpSolution1Permissions.Books.Default)); icon: "fa fa-file-alt" , return Task.CompletedTask; } ABP Suite appears to have partially removed the Authors menu entry but left orphaned code fragments, corrupting the file.

Expected behavior

When removing a navigation property and regenerating:

  1. The MenuContributor should remain valid C#
  2. Menu entries should be cleanly added or removed without leaving orphaned code
Actual behavior

ABP Suite corrupts the MenuContributor file when regenerating an entity after removing a navigation property, leaving invalid syntax that prevents compilation.

When I use WithDynamicOptions, I have issues that I don't have when using appsettings. I'll start with just ClientId. If I pull from appsettings, it works but if I remark out that line and use the Dynamic Option stored in the gui, I get the error "SecurityTokenInvalidAudienceException: IDX10208: Unable to validate audience. validationParameters.ValidAudience is null or whitespace and validationParameters.ValidAudiences is null." My end goal is to only set ClientId, ClientSecret, and TenantId in the dynamic External Provider properties. Then with TenantId, I'll build the Authority but could use help on how to do that.

            .AddOpenIdConnect("EntraId", "Microsoft Entra Id", options =>
            {
                options.Authority =  configuration["Authentication:EntraId:Instance"] + configuration["Authentication:EntraId:TenantId"] + "/v2.0/";
                //options.ClientId = configuration["Authentication:EntraId:ClientId"];
                options.ClientSecret = configuration["Authentication:EntraId:ClientSecret"];
                options.CallbackPath = configuration["Authentication:EntraId:CallbackPath"];
                
                options.ResponseType = OpenIdConnectResponseType.Code;
                options.SaveTokens = true;
                options.GetClaimsFromUserInfoEndpoint = true;
               
                options.Scope.Clear();
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Scope.Add("email");  
                
                options.ReturnUrlParameter = "returnUrl";                               
                
            })
            .WithDynamicOptions<OpenIdConnectOptions, OpenIdConnectHandler>("EntraId", options =>
            {
                options.WithProperty(o => o.ClientId);
                options.Properties.Add(new ExternalProviderDefinitionProperty
                {
                    PropertyName = "TenantId",
                    IsSecret = false
                });
            })

I'm using the code below to set my Entra ID values. I'm using AbpExternalProviderOptions instead of WithDynamicOptions so I can set the Tenant ID in the web gui and then build the Authority URL. The values get set in the database but how do we retrieve the "EntraId" ExternalProviderDefinition so we can access those property values when setting the OpenIdConnection options when using ABP Pro?

` Configure(options => { options.Definitions.Add(new ExternalProviderDefinition { Name = "EntraId", Properties = new List { new ExternalProviderDefinitionProperty { PropertyName = "ClientId", IsSecret = false }, new ExternalProviderDefinitionProperty { PropertyName = "ClientSecret", IsSecret = true }, new ExternalProviderDefinitionProperty { PropertyName = "CallbackPath", IsSecret = false }, new ExternalProviderDefinitionProperty { PropertyName = "DisplayName", IsSecret = false }, new ExternalProviderDefinitionProperty { PropertyName = "Enabled", IsSecret = false },new ExternalProviderDefinitionProperty { PropertyName = "TenantId", IsSecret = false } } });

});`

I figured out how to add it from extended file. I missed that I needed a new class that inherits from my entity's base class. What really confused me was in the documentation it provides this article. But this article was the key article as it provided the key info about creating a new class. Based on that articles breadcrumb, I'm not sure it's linked up correctly. I found it by searching and it really helped.

For anyone else, I'm not sure we can disable toolbar buttons. But once you override and wait for SetToolbarItemsAsync, you can then clear and add back the buttons you need.

protected override async ValueTask SetToolbarItemsAsync() { Toolbar.Contributors.Clear(); Toolbar.AddButton("Import users from excel", () => { //TODO: Write your custom code return Task.CompletedTask; }, "file-import", Blazorise.Color.Secondary); }

<br>

Thanks for the suggestions. Is there a way to add my toolbar buttons in the extended.razor.cs so it doesn't get overwritten if we use ABP Suite to make changes later?

On question #2, I'm not trying to change the order but the visibility. Is there a way to hide or disable the default Create button?

Thanks,

John

What's the best way to set the value of a navigational property so the create and edit always have that value. Here's an example. I have a Dealership entity and a Leads entity. Leads has a required navigational property of DealershipId. Here's what I have working.

On the Dealerships razor page, I added and EntityAction.

<EntityAction TItem="DealershipDto" Visible="@CanEditDealership" Clicked="async () => await NavigateToLeads(context)" Text="@L["Leads"]"></EntityAction>

In Dealerships.Extended.razor.cs I added

private Task NavigateToLeads(DealershipDto dealership) { NavigationManager.NavigateTo($"/leads?DealershipId={dealership.Id}"); return Task.CompletedTask; }

Then in LeadsAppService.Extended.cs, I have public async Task\<PagedResultDto> GetListByDealershipAsync(Guid dealershipId, PagedAndSortedResultRequestDto input) { var filterInput = new GetLeadsInput { DealershipId = dealershipId, Sorting = input.Sorting, MaxResultCount = input.MaxResultCount, SkipCount = input.SkipCount };

return await GetListAsync(filterInput); }

This works and gives me a new button to add a lead filtered on the selected dealership.

I tried following the guide in this article but all I could get to work was add buttons not removing or editing.

#1: Is this the best way to do this or is there an obvious "ABP way" that I'm missing?

#2 If it is the best way, how do I disable/hide the default create button (New Lead below)?

#3 On create and edit, how do I hide/disable the Dealership selector as we don't want any chance of it being changed before saving.

The answer to #1 may make questions 2 and 3 moot. Thanks for any help.

John

Thanks.

Sorry about that, yes...when using ABP Suite. Below you'll see Year and Mileage have default values. But if you check required on a property as I did on Year, the default value isn't populated. Uncheck Required and it starts populating the default value again.

  • ABP Framework version: v0.9.23
  • UI Type: Blazor Server
  • Database System: EF Core (SQL Server)
  • Tiered (for MVC) or Auth Server Separated (for Angular): No
  • Exception message and full stack trace:
  • Steps to reproduce the issue:

If you Save and Generate a property with a default value, the value will be set on new entries as long as Required isn't checked. If Required is checked, the default value isn't populated when creating a new record. If you uncheck Required and Save and Generate, Default Value will again be set when creating a new record.

Showing 1 to 10 of 13 entries
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.2.0-preview. Updated on February 05, 2026, 13:24
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.