ABP Framework

                              # Create a new layered application
                              abp new Acme.BookStore

                              # Create a new layered application using MongoDB
                              abp new Acme.BookStore -d mongodb

                              # Add a new module to the solution
                              abp add-module Volo.Blogging
                        
[DependsOn(
   typeof(AbpEntityFrameworkCoreModule), //Depending on a framework module
   typeof(MyBusinessModule) //Depending on your own module
)]
public class MyAppModule : AbpModule
{
   public override void ConfigureServices(ServiceConfigurationContext context)
   {
      //Configure DI and other modules...
   }

   public override void OnApplicationInitialization(ApplicationInitializationContext context)
   {
      //Perform some application initialization logic...
   }
}

Multi Tenancy

Code:
<abp-card>
   <img abp-card-image="Top" src="" data-src="/images/my-dog.png" class="lazy" loading="lazy"
width="250" heigth="162"/>
   <abp-card-body>
      <abp-card-title>Card title</abp-card-title>
      <abp-card-text>
            <p>
            This is a sample card component built by ABP bootstrap
            card tag helper. ABP has tag helper wrappers for most of
            the bootstrap components.
            </p>
      </abp-card-text>
      <a abp-button="Primary" href="javascript:void(0)"  >Go somewhere &rarr;</a>
   </abp-card-body>
</abp-card>
Result:

Bootstrap Tag Helper

Card title

This is a sample card component built by ABP bootstrap card tag helper.

Go somewhere →

View:
<abp-dynamic-form abp-model="@Model.PersonInput" submit-button="true" />
Model:
public class PersonModel
{
   [HiddenInput]
   public Guid Id { get; set; }

   [Required]
   [EmailAddress]
   [StringLength(255)]
   public string Email { get; set; }

   [Required]
   [StringLength(32)]
   [DataType(DataType.Password)]
   public string Password { get; set; }

   [StringLength(255)]
   public string Address { get; set; }

   public Gender Gender { get; set; }
}
Result:
public class Book : Entity<Guid>, IHasConcurrencyStamp
{
    public string ConcurrencyStamp { get; set; }

    //...
}
<abp-style-bundle name="MyGlobalBundle">
   <abp-style src="/libs/bootstrap/css/bootstrap.css" />
   <abp-style src="/libs/font-awesome/css/font-awesome.css" />
   <abp-style src="/libs/toastr/toastr.css" />
   <abp-style src="/styles/my-global-style.css" />
</abp-style-bundle>

Virtual File System

Theming

public class EmailSendingJob : BackgroundJob<EmailSendingArgs>
{
   private readonly IEmailSender _emailSender;

   public EmailSendingJob(IEmailSender emailSender)
   {
      _emailSender = emailSender;
   }

   public override void Execute(EmailSendingArgs args)
   {
      _emailSender.Send(
            args.EmailAddress,
            args.Subject,
            args.Body
      );
   }
}
public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase
{
    public PassiveUserCheckerWorker(
            AbpAsyncTimer timer,
            IServiceScopeFactory serviceScopeFactory
        ) : base(
            timer, 
            serviceScopeFactory)
    {
        Timer.Period = 6000;
    }

    protected async override Task DoWorkAsync(
        PeriodicBackgroundWorkerContext workerContext)
    {
        Logger.LogInformation("Starting: Setting status of inactive users...");

        //Resolve dependencies
        var userRepository = workerContext
            .ServiceProvider
            .GetRequiredService<IUserRepository>();

        //Do the work
        await userRepository.UpdateInactiveUserStatusesAsync();

        Logger.LogInformation("Completed: Setting status of inactive users...");
    }
}

Auto Rest APIs

//Call remote APIs just like local functions in JavaScript
acme.bookStore.book
   .getList({})
   .done(function (result) {
      //...
   });
Publish Events:
public class PublisherDemo : ITransientDependency
{
   private readonly IDistributedEventBus _distributedEventBus;

   public PublisherDemo(
      IDistributedEventBus distributedEventBus)
   {
      _distributedEventBus = distributedEventBus;
   }

   public async Task RunAsync()
   {
      //Publish an event
      await _distributedEventBus.PublishAsync(
            new StockCountChangedEvent(productId, 42)
      );
   }
}
Handle Events:
public class MyEventHandler
   : IDistributedEventHandler<StockCountChangedEvent>
{
   public Task HandleEventAsync(StockCountChangedEvent eventData)
   {
         //Handle the event and execute your business
   }
}
using Volo.Abp.DistributedLocking; 

namespace AbpDemo
{
    public class MyService : ITransientDependency
    {
      private readonly IAbpDistributedLock _distributedLock;
      
      public MyService(IAbpDistributedLock distributedLock)
        {
            _distributedLock = distributedLock;
        }

        public async Task MyMethodAsync()
        {
            await using (var handle = await _distributedLock.TryAcquireAsync("MyLockName"))
            {
                if (handle != null)
                {
                    // your code that access the shared resource
                }
            }   
        }
    }
}
public class MyService : ITransientDependency
{
   private readonly IBlobContainer _blobContainer;

   public MyService(IBlobContainer blobContainer)
   {
      _blobContainer = blobContainer;
   }

   public async Task SaveBytesAsync(byte[] bytes)
   {
      await _blobContainer.SaveAsync("my-blob", bytes);
   }

   public async Task<byte[]> GetBytesAsync()
   {
      return await _blobContainer.GetAllBytesOrNullAsync("my-blob");
   }
}
var result = await _templateRenderer.RenderAsync(
   "PasswordReset", //the template name
   new PasswordResetModel
   {
      Name = "john",
      Link = "https://abp.io/example-link?userId=123&token=ABC"
   }
);
public class MyService_Tests : AbpIntegratedTest<MyModule>
{
   private readonly MyService _myService;

   public MyService_Tests()
   {
      _myService = GetRequiredService<MyService>();
   }

   [Fact]
   public async Task MyService_Should_Do_It()
   {
      //Act
      var result = _myService.DoIt();

      //Assert
      result.ShouldBe(42);
   }
}
public class PersonService
{
   //Inject IObjectMapper
   private readonly IObjectMapper _objectMapper;

   public PersonService(IObjectMapper objectMapper)
   {
      _objectMapper = objectMapper;
   }

   public PersonDto GetPerson(Guid id)
   {
      Person person = GetPersonEntityFromRepository(id);

      //Use for Entity to DTO mapping
      return _objectMapper.Map<Person, PersonDto>(person);
   }
}
public async Task SendWelcomeEmailAsync(string emailAddress, string name)
{
   //Get the email template
   var template = await _emailTemplateProvider.GetAsync("WelcomeEmailTemplate");

   //Replace placeholders
   template.Replace("name", name);

   //Send email
   await _emailSender.SendAsync(
      emailAddress,
      "Welcome to our application!",
      template.Content
   );
}
{
   "culture": "en",
   "texts": {
      "WelcomeMessage": "Welcome to the application!",
      "HelloWorld":  "Hello World"
   }
}
//Convert a string to camelCase
"HelloWorld".ToCamelCase(); //returns "helloWorld"

//Truncate a string with "..." postfix
"This is a test string".TruncateWithPostfix(12); //returns "This is a..."

//Convert a string to int
"42".To<int>(); //returns 42 as int

//Check if a value occurs in a list
5.IsIn(1, 3, 5, 7); //returns true

//Check if a value is between a range
5.IsBetween(6, 12); //returns false
//Inherit from the AbpInterceptor to log all method executions
public class MyLoggingInterceptor : AbpInterceptor, ITransientDependency
{
   private readonly ILogger<MyLoggingInterceptor> _logger;

   public MyLoggingInterceptor(ILogger<MyLoggingInterceptor> logger)
   {
      _logger = logger;
   }

   public async override Task InterceptAsync(IAbpMethodInvocation invocation)
   {
      LogInvocation(invocation);
      await invocation.ProceedAsync();
   }

   private void LogInvocation(IAbpMethodInvocation invocation)
   {
      /* Access to all the information about the method execution
         * including method, class and provided arguments */

      _logger.LogInformation(
            "Executing the method: " +
            invocation.Method.Name +
            " of class " +
            invocation.TargetObject.GetType().FullName
      );
   }
}
/* Automatically registers MyService as transient.
* Then you can inject by IMyService or MyService.
*/
public class MyService : IMyService, ITransientDependency
{
}
public class MyEntity : Entity<Guid>, ISoftDelete
{
   public bool IsDeleted { get; set; }
}
 public class MyService : DomainService
 {
     protected IStringEncryptionService StringEncryptionService { get; }

     public MyService(IStringEncryptionService stringEncryptionService)
     {
         StringEncryptionService = stringEncryptionService;
     }

     public string Encrypt(string value)
     {
         // To enrcypt a value
         return StringEncryptionService.Encrypt(value);
     }

     public string Decrpyt(string value)
     {
         // To decrypt a value
         return StringEncryptionService.Decrypt(value);
     }
 }