Activities of "enisn"

Hi,

ITextTemplateDefinitionManager is implemented here: https://github.com/abpframework/abp/blob/605482916e6f87b75d5a23a76ba2299fb72c9306/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs#L9

And it uses IStaticTemplateDefinitionStore and IDynamicTemplateDefinitionStore.

And Dynamic one doesn't have any real implementation. The NullIDynamicTemplateDefinitionStore was resolved when injected:

https://github.com/abpframework/abp/blob/605482916e6f87b75d5a23a76ba2299fb72c9306/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs#L9

You may implement your own DynamicTemplateDefinitionStore class by implementing IDynamicTemplateDefinitionStore interface that writes/read from a database table.

Something like that:

public class DatabaseTemplateDefinitionStore : IDynamicTemplateDefinitionStore, ITransientDependency
{
    protected IRepository<TemplateDefinitionEntity, Guid> TemplateDefinitionRepository { get; }

    public DatabaseTemplateDefinitionStore(IRepository<TemplateDefinition, Guid> templateDefinitionRepository)
    {
        TemplateDefinitionRepository = templateDefinitionRepository;
    }

    public async Task<TemplateDefinition> GetAsync(string name)
    {
        var entity = await TemplateDefinitionRepository.GetAsync(name);
        return MapToTemplateDefinitionAsync(entity); // Map to TemplateDefinition in your own way
    }

    public async Task<IReadOnlyList<TemplateDefinition>> GetAllAsync()
    {
        var list = await TemplateDefinitionRepository.GetListAsync();
        return list.Select(MapToTemplateDefinitionAsync).ToImmutableList(); // Map to TemplateDefinition in your own way
    }

    public async Task<TemplateDefinition?> GetOrNullAsync(string name)
    {
        var entity = await TemplateDefinitionRepository.FindAsync(name);

        return entity == null ? null : MapToTemplateDefinitionAsync(entity); // Map to TemplateDefinition in your own way
    }

    private TemplateDefinition MapToTemplateDefinitionAsync(TemplateDefinitionEntity entity)
    {
        // Implement your mapping logic here
        return new TemplateDefinition(entity.Name, entity.LocalizationResourceName, entity.DisplayName, entity.IsLayout, entity.Layout, entity.RenderEngine, entity.Properties);
    }
}

And create another AppService that creates it at runtime:


public class DynamicTemplateDefinitionAppService : IDynamicTemplateDefinitionStore, ITransientDependency
{
    protected IRepository<TemplateDefinitionEntity, Guid> TemplateDefinitionRepository { get; }

    public DynamicTemplateDefinitionAppService(IRepository<TemplateDefinition, Guid> templateDefinitionRepository)
    {
        TemplateDefinitionRepository = templateDefinitionRepository;
    }

    public async Task CreateAsync(TemplateDefinitionDto input)
    {
        var entity = new TemplateDefinitionEntity(input.Name, input.LocalizationResourceName, input.DisplayName, input.IsLayout, input.Layout, input.RenderEngine, input.Properties);
        await TemplateDefinitionRepository.InsertAsync(entity);
    }

    // all other CRUD methods can be implemented similarly
}

Hi,

Sorry to hear that. Updating client-proxies might be required. Can you check if your client-proxies are updated? https://abp.io/docs/latest/framework/ui/angular/service-proxies

Our @angularteam will help you better in this issue soon.

Hi,

In the Blazor, icons are coming from blazorise and it seems it's related to Blazorise.

For the official ABP v9.1 packages it seems we are dependent on Blazorise 1.6.2. https://github.com/abpframework/abp/blob/ea46c04b56a4dded54fe1fd684cc89ef4094352b/Directory.Packages.props#L20

Can you try downgrading to 1.6.2 in your application?

If you directly use DomainServices instead of using AppServices, you will bypass the permission checks, you can check how they're implemented and apply the same logic in your service, or you can use IdentityUserManager in your code by injecting it.

It extends UserManager<> from Microsoft.AspNetCore.Identity

https://github.com/abpframework/abp/blob/af1e92c5aff2d7ad9991fd46a0f2eed4bf4f559c/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs#L74

Hi,

I need to ask some additional questions.

  1. Can you check the publisher RabbitMQ configuration is correct from the appsettings.json?

  2. Also if you have different applications, make sure you're using the exact same CustomerUpdatedEto class from 2 different projecsts.

    • Make sure depending on .Contracts package where CustomerUpdatedEto is located from subscriber project.
  3. Try adding [Serialize] attribute over CustomerUpdatedEto class

    [Serializable]
    [EventName("MyProject.CustomerService.Customers.CustomerUpdated")]
    public class CustomerUpdatedEto : EtoBase
    {
        // ...
    }
    
  4. In your example I see IDistributedEventHandler but there is no such an interface in ABP Framework. It should be IDistributedEventHandler<TEvent>, can you try using it as it is like IDistributedEventHandler<CustomerUpdatedEto>

  5. Do you see any logs in the publisher application logs whenever you publish an event? There might be an error that can help to find problem.

  6. Do you use Microservice solution or is Outbox/Inbox pattern enabled in your application?

Hi,

ABP already has a built-in system for managing 2FA through settings, which can be configured globally or per tenant:

// In Account Admin UI
await SettingManager.SetForCurrentTenantAsync(IdentityProSettingNames.TwoFactor.Behaviour, input.TwoFactorBehaviour.ToString());

We already set is per each tenant. So you can manage it through settings.

Google Authenticator is already supported built-in, you do not have to take any action: https://abp.io/docs/latest/modules/identity/two-factor-authentication#verification-providers

Just enable it and start using.

Remember, users should have a verified e-mail or phone number to activate 2FA.


As a second question, to SMS integration ABP has an infrastructure for it and has an implementation with Twilio: https://abp.io/docs/latest/modules/twilio-sms

But if you wish to use Infobip you should implment it on your own:

  • Add Volo.Abp.Sms nuget package to your project:
abp add-package Volo.Abp.Sms
  • Create InfobipSmsSender that implements ISmsSender
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ISmsSender))]
public class InfobipSmsSender : ISmsSender, ITransientDependency
{
    private readonly IConfiguration _configuration;
    private readonly HttpClient _httpClient;

    public InfobipSmsSender(IConfiguration configuration, IHttpClientFactory httpClientFactory)
    {
        _configuration = configuration;
        _httpClient = httpClientFactory.CreateClient("Infobip");
    }

    public async Task SendAsync(SmsMessage smsMessage)
    {
        var baseUrl = _configuration["Infobip:BaseUrl"];
        var apiKey = _configuration["Infobip:ApiKey"];
        var sender = _configuration["Infobip:Sender"];

        var requestBody = new
        {
            messages = new[]
            {
                new
                {
                    from = sender,
                    destinations = new[] { new { to = smsMessage.PhoneNumber } },
                    text = smsMessage.Text
                }
            }
        };

        var request = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/sms/2/text/advanced")
        {
            Content = new StringContent(JsonSerializer.Serialize(requestBody), Encoding.UTF8, "application/json")
        };

        request.Headers.Add("Authorization", $"App {apiKey}");

        await _httpClient.SendAsync(request);
    }
}
  • And the appsettings.json:
{
  "Infobip": {
    "BaseUrl": "https://api.infobip.com",
    "ApiKey": "your-api-key",
    "Sender": "YourApp"
  }
}

Account Pro module uses ISmsSender interface to send Security Code and Confirmation Code, so implementing this interface is enough to make it work.

Hi,

You use [AllowAnonymous] attribute on your controller but it seems you're using another appservices in your controller. Each appservice checks their own permissions. _userAppService field in your code is probably injected as IUserAppService and that app service has their own [Authorize] attribute or permission checks in their methods. If you want to bypass permission checks, you may want to use Repositories directly inside application services.


You can see it has its own permission to execute method: https://github.com/abpframework/abp/blob/af1e92c5aff2d7ad9991fd46a0f2eed4bf4f559c/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs#L160

Hi,

I checked the File-management module and found some ways to do it.

If you have access to the source code, I can** recommend to you downloading the source** code and take a look at to source code to find another implementation that fits your requirements better.

As I understand the case, the following way should work:

Looking at the code, the key components we need to modify are:

  • The FileDescriptorAppService which uses IBlobContainer<FileManagementContainer>
  • The DirectoryDescriptorAppService which manages the directory structure

  • First, create a custom blob container selector service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Users;

namespace AbpSolution;

public interface IBlobContainerSelector
{
    Task<string> GetCurrentContainerNameAsync();
}

public class YourBlobContainerSelector : IBlobContainerSelector, ITransientDependency
{
    private readonly ICurrentUser _currentUser;
    private readonly ICurrentTenant _currentTenant;

    public YourBlobContainerSelector(
        ICurrentUser currentUser,
        ICurrentTenant currentTenant)
    {
        _currentUser = currentUser;
        _currentTenant = currentTenant;
    }

    public async Task<string> GetCurrentContainerNameAsync()
    {
        // Implement your logic to select the container
        // This could be based on user selection, tenant, or other criteria
        return "selected-container-name";
    }
}
  • Create a custom blob container factory:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Users;

namespace AbpSolution;

public interface ICustomBlobContainerFactory
{
    Task<IBlobContainer> GetContainerAsync();
}

public class CustomBlobContainerFactory : ICustomBlobContainerFactory
{
    private readonly IBlobContainerSelector _containerSelector;
    private readonly IBlobContainerFactory _blobContainerFactory;

    public CustomBlobContainerFactory(
        IBlobContainerSelector containerSelector,
        IBlobContainerFactory blobContainerFactory)
    {
        _containerSelector = containerSelector;
        _blobContainerFactory = blobContainerFactory;
    }

    public async Task<IBlobContainer> GetContainerAsync()
    {
        var containerName = await _containerSelector.GetCurrentContainerNameAsync();
        return _blobContainerFactory.Create(containerName);
    }
}
  • Override the FileDescriptorAppService:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Volo.Abp.Features;
using Volo.Abp.ObjectExtending;
using Volo.FileManagement.Authorization;
using Volo.FileManagement.Files;

namespace Volo.FileManagement.Directories;

[RequiresFeature(FileManagementFeatures.Enable)]
[Authorize(FileManagementPermissions.DirectoryDescriptor.Default)]
public class DirectoryDescriptorAppService : FileManagementAppService, IDirectoryDescriptorAppService
{
    protected IDirectoryManager DirectoryManager { get; }
    protected IDirectoryDescriptorRepository DirectoryDescriptorRepository { get; }
    protected IFileManager FileManager { get; }
    protected IFileDescriptorRepository FileDescriptorRepository { get; }

    protected FileIconOption FileIconOption { get; }

    public DirectoryDescriptorAppService(
        IDirectoryManager directoryManager,
        IFileManager fileManager,
        IDirectoryDescriptorRepository directoryDescriptorRepository,
        IFileDescriptorRepository fileDescriptorRepository,
        IOptions<FileIconOption> fileIconOption)
    {
        DirectoryManager = directoryManager;
        FileManager = fileManager;
        DirectoryDescriptorRepository = directoryDescriptorRepository;
        FileDescriptorRepository = fileDescriptorRepository;

        FileIconOption = fileIconOption.Value;
    }

    public virtual async Task<DirectoryDescriptorDto> GetAsync(Guid id)
    {
        var directoryDescriptor = await DirectoryDescriptorRepository.GetAsync(id);

        return ObjectMapper.Map<DirectoryDescriptor, DirectoryDescriptorDto>(directoryDescriptor);
    }

    public virtual async Task<ListResultDto<DirectoryDescriptorInfoDto>> GetListAsync(Guid? parentId)
    {
        var subDirectories = await DirectoryDescriptorRepository.GetChildrenAsync(parentId);

        var result = new List<DirectoryDescriptorInfoDto>();

        foreach (var subDirectory in subDirectories)
        {
            result.Add(new DirectoryDescriptorInfoDto
            {
                Name = subDirectory.Name,
                Id = subDirectory.Id,
                ParentId = subDirectory.ParentId,
                HasChildren = await DirectoryDescriptorRepository.ContainsAnyAsync(subDirectory.Id, false)
            });
        }

        return new ListResultDto<DirectoryDescriptorInfoDto>(result);
    }

    [Authorize(FileManagementPermissions.DirectoryDescriptor.Create)]
    public virtual async Task<DirectoryDescriptorDto> CreateAsync(CreateDirectoryInput input)
    {
        var directoryDescriptor = await DirectoryManager.CreateAsync(input.Name, input.ParentId, CurrentTenant.Id);

        input.MapExtraPropertiesTo(directoryDescriptor);

        await DirectoryDescriptorRepository.InsertAsync(directoryDescriptor);

        return ObjectMapper.Map<DirectoryDescriptor, DirectoryDescriptorDto>(directoryDescriptor);
    }

    [Authorize(FileManagementPermissions.DirectoryDescriptor.Update)]
    public virtual async Task<DirectoryDescriptorDto> RenameAsync(Guid id, RenameDirectoryInput input)
    {
        var directory = await DirectoryDescriptorRepository.GetAsync(id);

        directory.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp);

        await DirectoryManager.RenameAsync(directory, input.Name);
        await DirectoryDescriptorRepository.UpdateAsync(directory);

        return ObjectMapper.Map<DirectoryDescriptor, DirectoryDescriptorDto>(directory);
    }

    public virtual async Task<PagedResultDto<DirectoryContentDto>> GetContentAsync(DirectoryContentRequestInput input)
    {
        var result = new List<DirectoryContentDto>();
        var subDirectoryCount = await DirectoryDescriptorRepository.GetChildrenCountAsync(input.Id, input.Filter);
        var subFileCount = await FileDescriptorRepository.CountDirectoryFilesAsync(input.Id, input.Filter);

        // directory can be orderable for only its name
        var directorySorting =
                input.Sorting?.IndexOf("name asc", StringComparison.OrdinalIgnoreCase) >= 0 ?
                "name asc" :
                input.Sorting?.IndexOf("name desc", StringComparison.OrdinalIgnoreCase) >= 0 ?
                "name desc" :
                null;

        var subDirectories = await DirectoryDescriptorRepository.GetChildrenAsync(input.Id, input.Filter, directorySorting, input.MaxResultCount, input.SkipCount);
        result.AddRange(ObjectMapper.Map<List<DirectoryDescriptor>, List<DirectoryContentDto>>(subDirectories));

        if (await AuthorizationService.IsGrantedAsync(FileManagementPermissions.FileDescriptor.Default))
        {
            var fileSkipCount = input.SkipCount <= subDirectoryCount ? 0 : input.SkipCount - subDirectoryCount;
            var fileMaxResultCount = input.MaxResultCount - subDirectories.Count;

            var subFiles = await FileDescriptorRepository.GetListAsync(input.Id, input.Filter, input.Sorting, fileMaxResultCount, fileSkipCount);
            var subFilesDto = ObjectMapper.Map<List<FileDescriptor>, List<DirectoryContentDto>>(subFiles);
            foreach (var fileDto in subFilesDto)
            {
                fileDto.IconInfo = FileIconOption.GetFileIconInfo(fileDto.Name);
                
                result.Add(fileDto);
            }
        }

        return new PagedResultDto<DirectoryContentDto>(subDirectoryCount + subFileCount, result);
    }

    [Authorize(FileManagementPermissions.DirectoryDescriptor.Delete)]
    public virtual async Task DeleteAsync(Guid id)
    {
        await DirectoryManager.DeleteAsync(id);
    }

    [Authorize(FileManagementPermissions.DirectoryDescriptor.Update)]
    public virtual async Task<DirectoryDescriptorDto> MoveAsync(MoveDirectoryInput input)
    {
        var directory = await DirectoryDescriptorRepository.GetAsync(input.Id);

        directory.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp);

        await DirectoryManager.MoveAsync(directory, input.NewParentId);
        await DirectoryDescriptorRepository.UpdateAsync(directory);

        return ObjectMapper.Map<DirectoryDescriptor, DirectoryDescriptorDto>(directory);
    }
}
  • Configure the blob containers in your module class:
 Configure<AbpBlobStoringOptions>(options =>
 {
     // Configure your blob containers
     options.Containers.Configure("container1", container =>
     {
         container.UseDatabase();
         // Add other configuration as needed
     });

     options.Containers.Configure("container2", container =>
     {
         container.UseAzure(options => {  /* ... */});
         // Add other configuration as needed
     });
     
    // ...and more...
 });

Hi,

Can you share how you configured your Background Jobs in your each application? Including .Web and .Web_Int

Normally, if you disable job execution, it shouldn't even be triggered. It seems some misconfiguration.

Hi,

Can you share your Node.js, Yarn and npm versions?

# get node version
node -v

# get yarn version
yarn -v

# get npm version
npm -v

Check if your node & yarn version matches with Pre-requirements documentation: https://abp.io/docs/latest/get-started/pre-requirements#node-js-and-yarn

ABP uses classic yarn, which is Yarn v1.22+. Make sure this is correct.

Showing 111 to 120 of 784 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.1.0-preview. Updated on December 17, 2025, 07:08
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.