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...
}
}
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 →</a>
</abp-card-body>
</abp-card>
Result:

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>
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...");
}
}
//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);
}
}