Open Closed

Overriding Service DTOs : Remove properties #944


0
raif created
  • ABP Framework version: v4.2.1
  • UI type: MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): yes

https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Overriding-Services

Hello, I want to override the method in the application service which in a seperate module.

using Volo.Saas.Editions;
using Volo.Saas.Host.Dtos;
using Volo.Saas.Tenants;

namespace Volo.Saas.Host
{
    [Authorize(SaasHostPermissions.Tenants.Default)]
    public class TenantAppService : SaasHostAppServiceBase, ITenantAppService
    {
        public TenantAppService(.........
        )

        [Authorize(SaasHostPermissions.Tenants.Create)]
        public virtual async Task<SaasTenantDto> CreateAsync(SaasTenantCreateDto input)
        {
        }
    }
}

I'm just targeting to override CreateAsync in my solution

[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITenantAppService), typeof(TenantAppService), typeof(NMMTenantAppService))]
public class NMMTenantAppService : TenantAppService
{
    public NMMTenantAppService(
        IEditionRepository editionRepository, 
        ITenantRepository tenantRepository, 
        ITenantManager tenantManager, 
        IDataSeeder dataSeeder)
        : base(
              tenantRepository: tenantRepository, 
              editionRepository: editionRepository, 
              tenantManager: tenantManager, 
              dataSeeder: dataSeeder)
    {

    }

    public async override Task<SaasTenantDto> CreateAsync(SaasTenantCreateDto input)
    {
        var tenant = await TenantManager.CreateAsync(input.Name, input.EditionId);
        input.MapExtraPropertiesTo(tenant);
        await TenantRepository.InsertAsync(tenant);

        await CurrentUnitOfWork.SaveChangesAsync();

        return ObjectMapper.Map<Tenant, SaasTenantDto>(tenant);
    }
}

Beside that I'm also not happy with** SaasTenantCreateDto**. Tricky part is I don't want to extend DTO, I want to remove properties What is the recommended way to do this in framework ?

Do I need create a new ApplicationService in my project with new interface ? And replace service from module with a new one

App Service

[Authorize(SaasHostPermissions.Tenants.Default)]
public class NMMTenantAppService : SaasHostAppServiceBase, INMMTenantAppService
{
}

Method

[Authorize(SaasHostPermissions.Tenants.Create)]
public async Task<SaasTenantDto> CreateAsync(**NMMSaasTenantCreateDto** input)
{

}

Interface

public interface INMMTenantAppService : ICrudAppService<SaasTenantDto, Guid, GetTenantsInput, **NMMSaasTenantCreateDto**, SaasTenantUpdateDto>
{

}

Dto

public class NMMSaasTenantCreateDto : SaasTenantCreateOrUpdateDtoBase
{
}

4 Answer(s)
  • 0
    raif created

    Is there any posibility that we can add attribute which prevents serialization of property ? How can i remove attribute from property ?

    public static class NMMApplicationContractsExtensionConfigurator
    {
        private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
    
        public static void Configure()
        {
            OneTimeRunner.Run(() =>
            {
                ConfigureProperties();
            });
        }
        
        private static void ConfigureProperties()
        {
            ObjectExtensionManager.Instance.AddOrUpdateProperty<SaasTenantCreateDto, string>("AdminEmailAddress",
                 options =>
                 {
                     options.Attributes.Add(new System.Text.Json.Serialization.JsonIgnoreAttribute());
                     options.Attributes.Remove(new StringLengthAttribute(256));
                     options.Attributes.Add(new StringLengthAttribute(3)
                     {
                         MinimumLength = 1
                     }
                 );
            });
         }
    }
    

    Definition done at PreConfigure step

    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        NMMApplicationContractsExtensionConfigurator.Configure();
    } 
    

    However, still able to pass validation, that means i couldn't change DTO properties

  • 0
    hikalkan created
    Support Team

    Hi,

    Unfortunately, removing a property is not possible and we've never thought such a requirement before. AddOrUpdateProperty is for extra properties, not for the properties of a class. As you know, normally, no way to remove a class property on runtime. As I know, also there is no way to remove an attribute on runtime.

    I suggest you to create a new method in your custom service and use it in the client side.

    As an alternative, you can add [DisableValidation] attribute to the CreateAsync method to disable validation. In this case, you can implement the validation yourself inside the method.

  • 0
    raif created

    Thx for the response. Please consider my comment as feedback. Volo.Saas.Host Tenant app service has create method which includes user data seeding operation.

    public virtual async Task<SaasTenantDto> CreateAsync(SaasTenantCreateDto input)
    {
    	var tenant = await TenantManager.CreateAsync(input.Name, input.EditionId);
    	input.MapExtraPropertiesTo(tenant);
    	await TenantRepository.InsertAsync(tenant);
    
    	await CurrentUnitOfWork.SaveChangesAsync();
    
    	using (CurrentTenant.Change(tenant.Id, tenant.Name))
    	{
    		//TODO: Handle database creation?
    
    		await DataSeeder.SeedAsync(
    			new DataSeedContext(tenant.Id)
    				.WithProperty("AdminEmail", input.AdminEmailAddress)
    				.WithProperty("AdminPassword", input.AdminPassword)
    		);
    	}
    
    	return ObjectMapper.Map<Tenant, SaasTenantDto>(tenant);
    }
    

    And it automatically assumes that all tenants use a shared database which is not the %100 cases. In my case i would like assign seperate database for each tenant and method seeds users to the host AbpUsers table.

    Beside that DTO has no property about connection string apart from admin email and password which is also not cool

    I think it would be better if you leave the workflow of the database seed operation to the developers.But ofc it may depend logical reason which is not able to understand yet. It just feedback

    Another question is I am sure that I have removed the TENANTAPPSERVICE and TENANTCONTROLLER from registered service.

    Why swagger still listing volo.saas.host.tenant endpoints ? I also don't use ConventionalControllers.Create method in my HttpApiHostModule. Any hint ?

  • 0
    raif created

    Good job about those Auto Api Controller and documentation https://docs.abp.io/en/abp/latest/API/Auto-API-Controllers cheers

    However my IQ level is not high enough to get it first glance