I have been following the guide on how to customize the app modules with the intention of extending module entities with new properties and exposing these with a modified service/controller .
I have extended OrganizationUnit from a module with the following properties:
and then mapped these new properties to the same database table as OrganizationUnit by updating DbContext.OnModelCreating and EfCoreEntityExtensionMappings and and Dto Extensions and created a database-migration

And here is user interface for inserting new organization unit and its work fine

Summary
To summarize, I wish to achieve the following:

How do I add new method from applications services and controllers in a way that enables me to get list of UnitCategory as dropdown list? I have implemented the following based on the solution #438 :
public interface IAppOrganizationUnitAppService : IOrganizationUnitAppService
{
Task<PagedResultDto<LookupDto>> GetUnitCategoryLookupAsync(LookupRequestDto input);
}
[RemoteService(IsEnabled = false)] // If you use dynamic controller feature you can disable remote service. Prevent creating duplicate controller for the application service.
[Dependency(ReplaceServices = true)]
[ExposeServices( typeof(OrganizationUnitAppService),typeof(IAppOrganizationUnitAppService))]
public class AppOrganizationUnitAppService : OrganizationUnitAppService, IAppOrganizationUnitAppService
{
private readonly IMODRepository<OrganizationUnitCategory, Guid> _unitCategoryRepository;
public AppOrganizationUnitAppService(
OrganizationUnitManager organizationUnitManager,
IdentityUserManager userManager,
IOrganizationUnitRepository organizationUnitRepository,
IIdentityUserRepository identityUserRepository,
IIdentityRoleRepository identityRoleRepository,
IMODRepository<OrganizationUnitCategory, Guid> unitCategoryRepository)
:base(organizationUnitManager,userManager, organizationUnitRepository, identityUserRepository, identityRoleRepository)
{
_unitCategoryRepository = unitCategoryRepository;
}
public async Task<PagedResultDto<LookupDto>> GetUnitCategoryLookupAsync(LookupRequestDto input)
{
var query = _unitCategoryRepository.AsQueryable()
.WhereIf(!string.IsNullOrWhiteSpace(input.Filter), x => x.ArabicName != null && x.ArabicName.Contains(input.Filter));
var lookupData = await query.PageBy(input.SkipCount, input.MaxResultCount).ToDynamicListAsync<OrganizationUnitCategory>();
var totalCount = query.Count();
return new PagedResultDto<LookupDto>
{
TotalCount = totalCount,
Items = ObjectMapper.Map<List<OrganizationUnitCategory>, List<LookupDto>>(lookupData)
};
}
}
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(OrganizationUnitController), typeof(IAppOrganizationUnitAppService))]
[RemoteService(true, Name = "AbpIdentity")]
[Route("api/identity/organization-units", Order = 0)]
[ControllerName("OrganizationUnit")]
[Area("identity")]
public class AppOrganizationUnitController : OrganizationUnitController, IAppOrganizationUnitAppService
{
public AppOrganizationUnitController(IOrganizationUnitAppService organizationUnitAppService)
: base(organizationUnitAppService)
{
}
[HttpGet]
[Route("Unit-Category-lookup")]
public Task<PagedResultDto<LookupDto>> GetUnitCategoryLookupAsync(LookupRequestDto input)
{
return ((IAppOrganizationUnitAppService)OrganizationUnitAppService).GetUnitCategoryLookupAsync(input);
}
}
However when I attempt to start the HttpApi.Host project I now get the following exception:

- ABP Framework version: v3.2.0
- UI type: Angular
- Tiered (MVC) or Identity Server Seperated (Angular): Identity Server Seperated (Angular)
- Exception message and stack trace:
- Steps to reproduce the issue:
7 Answer(s)
-
0
hi
In the current version, there's automatic way of making a combobox for navigation property. But it's in our roadmap.

AppOrganizationUnitController has not been registeredthis exception is weird! becauseAppOrganizationUnitControlleris derived fromOrganizationUnitControllerwhich is derived fromAbpController. so it must be already registered to the DI system.public class OrganizationUnitController : AbpController, IOrganizationUnitAppService, IApplicationService, IRemoteServicedid you create the controller in
*.HttpApi -
0
Yes I created the controller in
*.HttpApi -
0
I guess you don't need to put
GetUnitCategoryLookupAsyncintoAppOrganizationUnitController. You can create a new controller. Can you try it. -
0
Hi, I have created this controller only to inlcude
GetUnitCategoryLookupAsyncand I need it to be appear under the same path in swagger. If I put it under a new controller, it will create it under a new path ,and I guess combobox won't appear in UI !!I am really stuck with this issue. I would be appreciative if you could help me with it.
-
0
there won't be a combobox even if you implement this. As I mentioned, this feature will come in the next releases. (4.1) what you can do is; you can replace the New Organisation razor page.
This document explains how to customize UI => https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface
If you create your own view in the
Pages/Identity/OrganizationUnitsdirectory (as embedded resource) it'll overwrite the existing pageCreate
CreateModal.cshtmlfile in your web project underPages/Identity/OrganizationUnits/CreateModal.cshtmlAdd the below code to your
CreateModal.cshtmland make your customizationsCreateModal.cshtml
@page @using Microsoft.AspNetCore.Mvc.Localization @using Microsoft.Extensions.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @using Volo.Abp.Identity.Localization @using Volo.Abp.Identity.Web.Pages.Identity.OrganizationUnits @using Volo.Abp.Localization @using Volo.Abp.ObjectExtending @model CreateModalModel @inject IHtmlLocalizer<IdentityResource> L @inject IStringLocalizerFactory StringLocalizerFactory @{ Layout = null; } <form asp-page="/Identity/OrganizationUnits/CreateModal" autocomplete="off"> <abp-modal> <abp-modal-header title="@L["NewOrganizationUnit"].Value"></abp-modal-header> <abp-modal-body> <abp-input asp-for="OrganizationUnit.ParentId"/> <abp-input asp-for="OrganizationUnit.DisplayName"/> @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties<CreateModalModel.OrganizationUnitInfoModel>()) { if (propertyInfo.Type.IsEnum) { <abp-select asp-for="OrganizationUnit.ExtraProperties[propertyInfo.Name]" label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"> </abp-select> } else { <abp-input type="@propertyInfo.GetInputType()" asp-for="OrganizationUnit.ExtraProperties[propertyInfo.Name]" label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)" asp-format="@propertyInfo.GetInputFormatOrNull()" value="@propertyInfo.GetInputValueOrNull(Model.OrganizationUnit.ExtraProperties[propertyInfo.Name])"/> } } </abp-modal-body> <abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer> </abp-modal> </form>
CreateModal.cshtml.cs
public class CreateModalModel : IdentityPageModel { [BindProperty] public OrganizationUnitInfoModel OrganizationUnit { get; set; } protected IOrganizationUnitAppService OrganizationUnitAppService { get; } public CreateModalModel(IOrganizationUnitAppService organizationUnitAppService) { OrganizationUnitAppService = organizationUnitAppService; OrganizationUnit = new OrganizationUnitInfoModel(); } public virtual Task OnGetAsync(Guid? parentId) { OrganizationUnit.ParentId = parentId; return Task.CompletedTask; } public virtual async Task<IActionResult> OnPostAsync() { ValidateModel(); var input = ObjectMapper.Map<OrganizationUnitInfoModel, OrganizationUnitCreateDto>(OrganizationUnit); await OrganizationUnitAppService.CreateAsync(input); return NoContent(); } public class OrganizationUnitInfoModel : ExtensibleObject { [HiddenInput] public Guid? ParentId { get; set; } [Required] public string DisplayName { get; set; } } } -
0
Hi,
Unfortunately, We are not using Razor UI for our project. We are using angular. I dont think it will be an easy task to replace organization unit component using the Replaceable Component Api. Is it?
-
0
If you are using Angular then check out https://docs.abp.io/en/commercial/latest/ui/angular/dynamic-form-extensions