Activities of "ageiter"

We're running ABP Framework 10.4 with an Angular 21 frontend. Our angular/ project uses Yarn Berry 4.12.0 (nodeLinker: node-modules in .yarnrc.yml), not Yarn Classic — this is required for our dependency setup (private npm registry scopes for FontAwesome Pro, etc.).

The problem: abp install-libs appears to only support/detect Yarn Classic 1.x, so our local setup script has to explicitly switch Yarn versions back and forth via Corepack around it:

corepack prepare yarn@1.22.22 --activate
abp install-libs

corepack prepare yarn@4.12.0 --activate
yarn install

This is fragile in practice: abp install-libs internally runs an unfrozen yarn install under whichever Yarn version is currently active. When it runs under Yarn 1, it silently rewrites yarn.lock back into the old v1 lockfile format. If the script is ever interrupted, or someone runs abp install-libs in isolation without the follow-up corepack prepare yarn@4.x --activate && yarn install, the repository can end up with a Yarn-1-format lockfile committed on top of a Yarn-Berry project — completely silently, since a plain local yarn install doesn't complain about it. This happened to us once and was hard to trace back.

Questions:

  • Is there a supported way to make abp install-libs work with an already-active Yarn Berry installation, instead of requiring Yarn 1 specifically?
  • Since the docs state install-libs is meant for MVC/Razor Pages/Blazor Server only — is it actually required at all for an Angular project, or is calling it in our setup script simply unnecessary legacy boilerplate we can drop?

Any clarification would help us remove this two-Yarn-version workaround entirely.

Thank you very much for the detailed explanation and code example :-) At the moment, we still need a bit more time to implement this. It isn’t a top priority just yet.

Wouldn’t that be a great feature for an extension to the ABP framework? A generic solution like that would probably be useful to many people and would be a useful addition. Please add it to the wish list :-)

We’d like to implement an undo/redo feature in our application. I’m aware that this can be a complex issue, particularly when dealing with dependent entities. And yet it’s a feature for which most applications require a solution.

Have you written anything on this subject before? (I haven’t been able to find anything, unfortunately)

How would you implement this using the existing ABP functionality?

EntityChanges and EntityPropertyChanges would certainly be one possible approach, but this is probably not quite enough to implement the functionality fully.

Would EF’s change tracking be suitable for storing the complete changes of a transaction, e.g. in a cache? Or does that stop working once you’ve called SaveChanges?

Do you have any ideas on how you would solve this (best practices) and whether there might already be something implemented in ABP that could be used?

Another big question is how to go about this when ‘delete cascading’ is configured… or when the entities are not fully audited entities.

I look forward to your answer.

Best, Adrian

Perfect, thank you :-)

A while back, I posted two feature requests under “ABP Suite feature requests”. Do you know if they were noted and, if so, whether they'll be implemented at some point?

https://abp.io/support/questions/8803/ABP-Suite-feature-request--2025#answer-3a20f067-49ef-b56a-6a66-0d1671aa7bf2

https://abp.io/support/questions/8803/ABP-Suite-feature-request--2025#answer-3a20f070-f3b8-a78e-2794-b2edbaa436b7

Thanks for the feedback. I've now successfully implemented it using a ...PagedListInput (the existing class) and ...ListInput (the new class with ISortedResultRequest). And I wanted to do it “correctly” from the start using the extended partial class, so I've also adapted that template.

A somewhat clunky but probably functional workaround might be to define a second input class in GetItemsInput.txt. However, I would prefer other solutions.

Server.AppService.GetItemsInput.txt:

using Volo.Abp.Application.Dtos;
using System;

namespace %%solution-namespace%%%%<if:ApplicationContractsNotExists>%%%%.AppServices%%</if:ApplicationContractsNotExists>%%.%%microservice-dtos-namespace-prefix%%%%entity-namespace%%
{
    public %%custom-code-abstract-modifier%% class Get%%entity-name-plural%%PagedInput%%custom-code-base%% : PagedAndSortedResultRequestDto
    {
        public string? FilterText { get; set; }

		%%property-definitions%%

        public Get%%entity-name-plural%%PagedInput%%custom-code-base%%()
        {
            
        }
    }

    public %%custom-code-abstract-modifier%% class Get%%entity-name-plural%%Input%%custom-code-base%%
    {
        public string? FilterText { get; set; }

		%%property-definitions%%

        public Get%%entity-name-plural%%Input%%custom-code-base%%()
        {
            
        }
    }
}

What we really miss in the entities generated by the ABP Suite is a GetList-Method that returns the data without pagination. By customizing certain templates, we have now added these missing methods ourselves.

Here are some examples of our customizations:

Server.Controller.ItemController.txt:

[HttpGet]
        public virtual Task<List<%%entity-name%%Dto>> GetListAsync(Get%%entity-name-plural%%Input input)
        {
            return _%%entity-name-plural-camelcase%%AppService.GetListAsync(input);
        }

        [HttpGet]
        [Route("paged")]
        public virtual Task<PagedResultDto<%%entity-name%%Dto>> GetPagedListAsync(Get%%entity-name-plural%%Input input)
        {
            return _%%entity-name-plural-camelcase%%AppService.GetPagedListAsync(input);
        }

Server.AppService.AppService.txt:

public virtual async Task<List<%%entity-name%%Dto>> GetListAsync(Get%%entity-name-plural%%Input input)
        {
            var items = await _%%entity-name-camelcase%%Repository.GetListAsync(input.FilterText, %%input-properties%%%%<if:HasFilterableProperties>%%, %%</if:HasFilterableProperties>%%input.Sorting);

            return ObjectMapper.Map<List<%%entity-name%%>, List<%%entity-name%%Dto>>(items);
        }

        public virtual async Task<PagedResultDto<%%entity-name%%Dto>> GetPagedListAsync(Get%%entity-name-plural%%Input input)
        {
            var totalCount = await _%%entity-name-camelcase%%Repository.GetCountAsync(input.FilterText%%<if:HasFilterableProperties>%%, %%</if:HasFilterableProperties>%%%%input-properties%%);
            var items = await _%%entity-name-camelcase%%Repository.GetListAsync(input.FilterText, %%input-properties%%%%<if:HasFilterableProperties>%%, %%</if:HasFilterableProperties>%%input.Sorting, input.MaxResultCount, input.SkipCount);

            return new PagedResultDto<%%entity-name%%Dto>
            {
                TotalCount = totalCount,
                Items = ObjectMapper.Map<List<%%entity-name%%>, List<%%entity-name%%Dto>>(items)
            };
        }

Here's my problem / my question:

For my GetListAsync method, I used the same input class that’s also used for the paged list. The problem, however, is that Angular requires a value to be set for MaxResultCount, even if that value isn’t used. This is poor design and confuses developers.

How could I use the ABP Suite to generate a custom input class for this? Ideally, of course, I’d be able to create a Server.AppService.GetItemsPagedInput.txt file in addition to the Server.AppService.GetItemsInput.txt template.

Is it possible to create your own templates? If so, where would they be saved?

Thanks, Adrian

Environment:

  • Template: app
  • Template Type: Classic
  • Created ABP Studio Version: 2.2.1
  • Current ABP Studio Version: 3.0.6
  • Tiered: No
  • Multi-Tenancy: Yes
  • UI Framework: angular
  • Theme: leptonx
  • Theme Style: system
  • Theme Menu Placement: side
  • Progressive Web App: No
  • Run Progressive Web App Support: No
  • Database Provider: ef
  • Database Management System: sqlserver
  • Separate Tenant Schema: Yes
  • Mobile Framework: none
  • Public Website: No
  • Social Login: Yes
  • Include Tests: Yes
  • Kubernetes Configuration: Yes
  • Distributed Event Bus: none
  • Use Local References: No
  • Optional Modules:
    • GDPR
    • FileManagement
    • TextTemplateManagement
    • LanguageManagement
    • AuditLogging
    • OpenIddictAdmin
  • Selected Languages: German (Switzerland), English, French, German (Germany), Italian
  • Default Language: German (Switzerland)
  • Create Command: abp new Bpo -t app --ui-framework angular --database-provider ef --database-management-system sqlserver --theme leptonx --separate-tenant-schema --skip-migration --skip-migrator --without-cms-kit --dont-run-install-libs --dont-run-bundling -file-management

Great, it works :-D

Thank you so much for the quick help! I wish I'd asked much sooner ;-)

Hi, thanks for this detailed answer. This is exactly the kind of solution I was looking for. I’ll be happy to test it out, and I think this is what I need.

_installer.InstallAsync() is relatively complex (recursive traversal and inserts across multiple repositories), so I can’t share it here. But if your approach doesn’t work, I’ll send you the code via email.

By the way: after 1000 inserts, I call await _unitOfWorkManager.Current!.SaveChangesAsync(). I also clear the DbContext’s ChangeTracker. The data is also fully present in the database. That’s why I suspect the problem might be in postprocessing (event pipeline).

Showing 11 to 20 of 335 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.8.0-preview. Updated on September 28, 2026, 11:44
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.