Activities of "enisn"

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.

Hi,

Some new templates don't have ABP Suite support right now.

Here 2 approaches you can follow:

  • Using ABP CLI
  • Using ABP Studio

Download via CLI

You can always download source codes with ABP CLI with the following command:

  • Download source code to .\account-pro-source folder:
abp get-source Volo.Abp.Account.Pro -o .\account-pro-source
  • Replace nuget packages with source code in your solution:
abp add-source-code Volo.Abp.Account.Pro --add-to-solution-file

Downloads the source into modules folder and adds local reference to your project by replacing nuget references

Replacing via ABP Studio

Follow;

  • Right click to Account.Pro from dependencies.
  • Choose "Replace with Source Code"
  • It automatically downloads the source code and replaces it for your project

ABP has an option for making ExchangeType as Fanout but it applies globally for the application. That means you can make it for all the events, not a particular event.

Configure<AbpRabbitMqEventBusOptions>(options =>{
    options.ExchangeType = ExchangeType.Fanout;
});

You'll need to configure it both published and subscriber applications.

Hi,

It's by design. The event handler is executed only once to prevent concurrent write operations at the same time.

It's the defaults of RabbitMQ. It uses kinda load-balancing operation across the subscribers and sends the event to only one single instance and awaits acknowledge (ACK) info to complete the event. If not, tries to send it again. It's the expected behaviour.

If your intent is for all instances to receive the event (for example, for broadcasting purposes), you’ll need to change the design slightly. A common approach is to use a publish/subscribe pattern with a fanout exchange. In this configuration, each service instance can have its own dedicated queue bound to the fanout exchange. Every time a message is published to the exchange, each bound queue gets its own copy of the message, and thus every instance can process it independently.

ABP Framework doesn't implement this fanout exchange logic since it's coupled to RabbitMQ and ABP uses abstraction over event-buses. That mean, you'll need to implement it on your own by using the RabbitMQ library itself instead using ABP abstractions.

The exception is thrown from there: https://github.com/abpframework/abp/blob/e23e92e8e181a093746d4d5d41e7ef2773a76ea5/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionManager.cs#L27

It should be get from StaticStore, but it seems there is a missing configuration and it's not defined. Can you make sure your HttpApi.Host project has direct or indirect reference to Volo.Abp.AuditLogging.Application.Contract package? Normally it should.

It seems some files are locked or cannot be accessed. Can you make sure ABP suite or ABP Studio isn't running while trying to open it with abp suite command.

(Windows only) Here what I can suggest if you're not sure which process is working.

taskkill /im dotnet* -f

And then try to execute abp suite command

Showing 111 to 120 of 779 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 October 30, 2025, 06:33