Issue: Proxies generated for already committed entities. There is no option for selective proxy generation in ABP Suite UI. Below is the same file in repo,”employee.service.ts”, before and after creating a new entity (any entity other than employee entity). 1. GetEmployeeLookup method was removed from code after proxy generation 2. Backend API URL is modified in multiple methods Method API URL Before API URL After getEmployeeGradeLookup /api/app/employees/grade-lookup /api/app/employees/employee-grade-lookup getEmployeeLocationLookup /api/app/employees/mapped-location-lookup /api/app/employees/employee-location-lookup getEmployeeRoleLookup /api/app/employees/role-lookup' /api/app/employees/employee-role-lookup getOrganizationUnitLookup /api/app/employees/org-unit-lookup /api/app/employees/organization-unit-lookup API URL Before is consistent with backend controller code. Attached are supporting versions of same “employee.service.ts” before and after new entity creation.employeeservicebefore.txt
4 Answer(s)
-
0
ABP Suite’s Angular proxy generation is not incremental and not selective: when you generate proxies, it regenerates the proxy files from the backend API Definition (
/api/abp/api-definition). Because of that, it can rewrite already-committed proxy files (remove methods, rename method URLs, etc.) if the server-side API surface it reads differs from what your previously generatedemployee.service.tswas based on.In ABP (including v10.4), the generated Angular URLs come from server metadata, not from the existing TypeScript file. So when you regenerate proxies, the tool will:
- drop methods that are no longer present (or no longer discoverable) in the API definition (e.g.,
GetEmployeeLookupdisappears), - update URL templates if the backend action’s “effective route” changed (or if the backend action name/route attributes changed), and overwrite the TS file accordingly.
- drop methods that are no longer present (or no longer discoverable) in the API definition (e.g.,
Practical resolution (to stop proxy generation from breaking already-committed code):
- Do not manually edit generated proxy files under
src/app/proxy/**. Treat them as generated artifacts. - Wrap/adapter pattern: create your own Angular service (e.g.,
employee-api.service.ts) that calls the generated proxy service, and only commit/use your wrapper in business code. Then proxy regeneration won’t break your app code, only the generated layer. - If you must keep stable URLs like
/api/app/employees/grade-lookupetc., make sure the backend controller/action routes are explicitly fixed with attributes (e.g.,[Route("api/app/employees")]on the controller +[HttpGet("grade-lookup")]on the action), and that these endpoints are visible in/api/abp/api-definition. Then regenerate proxies; the generated URLs will match those explicit routes.
- Do not manually edit generated proxy files under
If your backend code truly still has the old routes but the generator produces
/employee-grade-lookupstyle paths, that indicates the backend API definition being used during generation is not the one you think (common causes: generating against a different host/port, wrong environment, wrong gateway in tiered setup). Fix by generating proxies against the correct running endpoint that exposes the real API definition for that app.There is no ABP Suite UI option to generate proxies only for a single entity/service. (So the correct approach is to isolate generated files and rely on wrappers, or regenerate and commit generated output as a whole.)
Links (verified):
- https://docs.abp.io/en/abp/latest/UI/Angular/Service-Proxies
- https://abp.io/contact (for non-technical / license related requests)
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
The differences in
employee.service.tscome from how ABP names the navigation-property "lookup" endpoints, and that convention changed in ABP 10.3:- Before 10.3: the lookup is named after the related entity (
Grade→GetEmployeeGradeLookup/employee-grade-lookup), and multiple relations pointing to the same entity are merged into one — that's why your self-referenceGetEmployeeLookupwas dropped. - 10.3+: the lookup is named after the foreign-key property (
GradeId→GetGradeLookup/grade-lookup), and each relation, including each self-reference, keeps its own lookup.
Your committed file has the FK-style routes (
grade-lookup), but the regenerated one came out in the old entity-name style (employee-grade-lookup) with the self-reference gone. That's the pre-10.3 convention, so one of the tools you regenerate with is older than your project's ABP version (10.4).To pin down which one, could you share a few details:
- Your ABP Suite version (shown on the Suite start page), and
abp --version. - How the proxy gets regenerated — does it happen automatically when you create/save an entity in ABP Suite, or do you run
abp generate-proxy(or an@abp/ng.schematicscommand) yourself? - The
@abp/ng.coreand@abp/ng.schematicsversions from your Angularpackage.json. - If it's handy, the
navigationPropertiessection of.suite/entities/Employee.json— that shows exactly what the generator will produce for these lookups.
Once we see which piece is behind, the fix is to bring it up to your project's version (for example
abp suite updatefor Suite, or aligning the@abp/ng.*packages) and regenerate. The lookup routes then come back asgrade-lookup, the self-reference lookups aren't dropped, and the generated code stays consistent. One thing to expect: the method names line up with the routes too (getEmployeeGradeLookup→getGradeLookup), so you'll update those call sites in your Angular code once.On the "no selective generation" point — the proxy is regenerated as a whole, not per method, so regenerating always rewrites the file. Keeping the proxy folder in source control and reviewing the diff after each generation is the practical way to manage that.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Before 10.3: the lookup is named after the related entity (
-
0
ABP Suite Version: 10.4.1 Proxy generation happen automatically when you create/save an entity in ABP Suite @abp/ng.core: 10.4.1 @abp/ng.schematics: 10.4.1 PFB navigationProperties section of .suite/entities/Employee.json
"NavigationProperties": [ { "EntityNameWithDuplicationNumber": "Grade", "EntitySetNameWithDuplicationNumber": "EmployeeGrades", "ReferencePropertyName": "Grade", "UiPickType": "Dropdown", "IsRequired": true, "IncludeEntitiesFromModules": false, "FromAbpModule": false, "Name": "GradeId", "DisplayProperty": "Code", "Namespace": "Pulse.EmployeeGrades", "EntityName": "EmployeeGrade", "EntitySetName": "EmployeeGrades", "DtoNamespace": "Pulse.EmployeeGrades", "DtoEntityName": "EmployeeGradeDto", "Type": "Guid", "IsFilterable": true }, { "EntityNameWithDuplicationNumber": "Region", "EntitySetNameWithDuplicationNumber": "Regions", "ReferencePropertyName": "Region", "UiPickType": "Dropdown", "IsRequired": true, "IncludeEntitiesFromModules": false, "FromAbpModule": false, "Name": "RegionId", "DisplayProperty": "Name", "Namespace": "Pulse.Regions", "EntityName": "Region", "EntitySetName": "Regions", "DtoNamespace": "Pulse.Regions", "DtoEntityName": "RegionDto", "Type": "Guid", "IsFilterable": true }, { "EntityNameWithDuplicationNumber": "WorkingLocation", "EntitySetNameWithDuplicationNumber": "EmployeeLocations", "ReferencePropertyName": "WorkingLocation", "UiPickType": "Dropdown", "IsRequired": true, "IncludeEntitiesFromModules": false, "FromAbpModule": false, "Name": "WorkingLocationId", "DisplayProperty": "Name", "Namespace": "Pulse.EmployeeLocations", "EntityName": "EmployeeLocation", "EntitySetName": "EmployeeLocations", "DtoNamespace": "Pulse.EmployeeLocations", "DtoEntityName": "EmployeeLocationDto", "Type": "Guid", "IsFilterable": true }, { "EntityNameWithDuplicationNumber": "MappedLocation", "EntitySetNameWithDuplicationNumber": "EmployeeLocations1", "ReferencePropertyName": "MappedLocation", "UiPickType": "Dropdown", "IsRequired": true, "IncludeEntitiesFromModules": false, "FromAbpModule": false, "Name": "MappedLocationId", "DisplayProperty": "Name", "Namespace": "Pulse.EmployeeLocations", "EntityName": "EmployeeLocation", "EntitySetName": "EmployeeLocations", "DtoNamespace": "Pulse.EmployeeLocations", "DtoEntityName": "EmployeeLocationDto", "Type": "Guid", "IsFilterable": true }, { "EntityNameWithDuplicationNumber": "OrgUnit", "EntitySetNameWithDuplicationNumber": "OrganizationUnits", "ReferencePropertyName": "OrgUnit", "UiPickType": "Dropdown", "IsRequired": false, "IncludeEntitiesFromModules": true, "FromAbpModule": true, "Name": "OrgUnitId", "DisplayProperty": "DisplayName", "Namespace": "Volo.Abp.Identity", "EntityName": "OrganizationUnit", "EntitySetName": "OrganizationUnits", "DtoNamespace": "Volo.Abp.Identity", "DtoEntityName": "OrganizationUnitDto", "Type": "Guid", "IsFilterable": true }, { "EntityNameWithDuplicationNumber": "Role", "EntitySetNameWithDuplicationNumber": "EmployeeRoles", "ReferencePropertyName": "Role", "UiPickType": "Dropdown", "IsRequired": true, "IncludeEntitiesFromModules": false, "FromAbpModule": false, "Name": "RoleId", "DisplayProperty": "Name", "Namespace": "Pulse.EmployeeRoles", "EntityName": "EmployeeRole", "EntitySetName": "EmployeeRoles", "DtoNamespace": "Pulse.EmployeeRoles", "DtoEntityName": "EmployeeRoleDto", "Type": "Guid", "IsFilterable": true }, { "EntityNameWithDuplicationNumber": "TeamLead", "EntitySetNameWithDuplicationNumber": "Employees1", "ReferencePropertyName": "TeamLead", "UiPickType": "Dropdown", "IsRequired": false, "IncludeEntitiesFromModules": false, "FromAbpModule": false, "Name": "TeamLeadId", "DisplayProperty": "Name", "Namespace": "Pulse.Employees", "EntityName": "Employee", "EntitySetName": "Employees", "DtoNamespace": "Pulse.Employees", "DtoEntityName": "EmployeeDto", "Type": "Guid", "IsFilterable": true }, { "EntityNameWithDuplicationNumber": "ReportingManager", "EntitySetNameWithDuplicationNumber": "Employees2", "ReferencePropertyName": "ReportingManager", "UiPickType": "Dropdown", "IsRequired": false, "IncludeEntitiesFromModules": false, "FromAbpModule": false, "Name": "ReportingManagerId", "DisplayProperty": "Name", "Namespace": "Pulse.Employees", "EntityName": "Employee", "EntitySetName": "Employees", "DtoNamespace": "Pulse.Employees", "DtoEntityName": "EmployeeDto", "Type": "Guid", "IsFilterable": true }
API routes from EmployeeController: [HttpGet] [Route("grade-lookup")] public virtual Task<PagedResultDto<LookupDto<Guid>>> GetGradeLookupAsync(LookupRequestDto input) { return _employeesAppService.GetGradeLookupAsync(input); }
[HttpGet] [Route("region-lookup")] public virtual Task<PagedResultDto<LookupDto<Guid>>> GetRegionLookupAsync(LookupRequestDto input) { return _employeesAppService.GetRegionLookupAsync(input); }
[HttpGet] [Route("working-location-lookup")] public virtual Task<PagedResultDto<LookupDto<Guid>>> GetWorkingLocationLookupAsync(LookupRequestDto input) { return _employeesAppService.GetWorkingLocationLookupAsync(input); }
[HttpGet] [Route("mapped-location-lookup")] public virtual Task<PagedResultDto<LookupDto<Guid>>> GetMappedLocationLookupAsync(LookupRequestDto input) { return _employeesAppService.GetMappedLocationLookupAsync(input); }
[HttpGet] [Route("org-unit-lookup")] public virtual Task<PagedResultDto<LookupDto<Guid>>> GetOrgUnitLookupAsync(LookupRequestDto input) { return _employeesAppService.GetOrgUnitLookupAsync(input); }
[HttpGet] [Route("role-lookup")] public virtual Task<PagedResultDto<LookupDto<Guid>>> GetRoleLookupAsync(LookupRequestDto input) { return _employeesAppService.GetRoleLookupAsync(input); }
[HttpGet] [Route("team-lead-lookup")] public virtual Task<PagedResultDto<LookupDto<Guid>>> GetTeamLeadLookupAsync(LookupRequestDto input) { return _employeesAppService.GetTeamLeadLookupAsync(input); }
[HttpGet] [Route("reporting-manager-lookup")] public virtual Task<PagedResultDto<LookupDto<Guid>>> GetReportingManagerLookupAsync(LookupRequestDto input) { return _employeesAppService.GetReportingManagerLookupAsync(input); }
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Thanks for the details. Since everything is already on 10.4.1, my earlier upgrade suggestion was wrong — sorry about that. This is a bug in ABP Suite's Angular proxy generation: it names the navigation-property lookups differently from your backend controllers, so the generated URLs don't match and some lookups get dropped.
For now, generate the proxy from the running backend instead of Suite's built-in generation:
- Start your HTTP API host.
- From the
angularfolder, run (replace the URL with your host's URL):
abp generate-proxy -t ng -u https://localhost:44300 -m appThis reads your actual API, so
employee.service.tsmatches your controllers exactly and all the lookups are there. The method names follow the backend (getGradeLookupinstead ofgetEmployeeGradeLookup), so update those call sites once. If you regenerate the entity in Suite later, run this command again afterward.We'll fix this in Suite's Angular generation. Your ticket has been refunded.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)