×
Back to book

Custom business logic with C#Bot

This article will explore the different ways you can create custom business logic within C#Bot.

One benefit of the Codebots platform is that developers can take advantage of bot-written code to reduce boilerplate and redundant work, while increasing productivity and customisability with protected regions.

In C# architecure, business logic is performed as a service, and so this article will focus on how to implemenet custom business logic in the services, either by adding a new method to a C#Bot written service, or by implementing a new service and registering it.

Services

Services are a layer that sits on top of the data layer and are composed of complex business logic. In C#Bot, they can be found in the serverside/src/Services directory.

Here you can define custom services or methods for existing services to suit your domain or problem at hand. Each method can make use of multiple repositories or other services to solve a particular problem.

Continuing on with the Zoo user story used in previous lessons, let's say we want to create a service that updates the VetCheckStatus depending on the DateTime value of the LastVetCheck. We might want to add this to a service written by C# bot, or we might want to register it as a new service altogether.

Adding custom methods to C#Bot written services

Adding custom methods to existing services is as easy as finding a protected region, turning it on, and then implementing the service. Below is an example of the Vet Check Update added as a method inside of the C#Bot written CrudService in a protected region.

// % protected region % [Add extra functions in crudService] on begin
private const int VetCheckOverdueLimitInDays = 30;
private const int VetCheckRequiredLimitInDays = 20;

public async Task UpdateVetCheckStatus()
{
    var overdueDate = DateTime.Today.AddDays(-VetCheckOverdueLimitInDays);
    var requiredDate = DateTime.Today.AddDays(-VetCheckRequiredLimitInDays);

    await UpdateOverdue(overdueDate);
    await UpdateRequired(requiredDate, overdueDate);
}

private async Task UpdateOverdue(DateTime overdueDate)
{
    var overdueAnimals = await Get<Animal>()
        .Where(a => a.LastVetCheck < overdueDate && a.VetCheckStatus != VetCheckStatus.OVERDUE)
        .ToListAsync();
    overdueAnimals.ForEach(a => a.VetCheckStatus = VetCheckStatus.OVERDUE);
    await Update(overdueAnimals);
}

private async Task UpdateRequired(DateTime requiredDate, DateTime overdueDate)
{
    var requiredAnimals = await Get<Animal>()
        .Where(a => a.LastVetCheck == null
                    || (overdueDate < a.LastVetCheck && a.LastVetCheck < requiredDate && a.VetCheckStatus != VetCheckStatus.REQUIRED))
        .ToListAsync();
    requiredAnimals.ForEach(a => a.VetCheckStatus = VetCheckStatus.REQUIRED);
    await Update(requiredAnimals);
}
// % protected region % [Add extra functions in crudService] end

This example has been highly simplified for demonstration purposes. All services in C#Bot are guarded against C# Security which derives its security rule from the Security Diagram. Refer to Security in C#Bot for more details.

Adding new custom service Class to C#Bot written services

New services should be registered in the application startup to enable dependency injection from and into other services. C#Bot writes a protected region into the file Startup.cs where you can register your services and set the lifetime.

// % protected region % [Add extra startup methods here] on begin
services.AddScoped<AnimalService>();
// % protected region % [Add extra startup methods here] end

And here is an example of the Vet Check Update written as a new standalone service inside of a class. The CrudService dependency can be injected in since both CrudService and the custom AnimalService are both registered services.

namespace Zoo.Services
{
    public class AnimalService
    {
        private const int VetCheckOverdueLimitInDays = 30;
        private const int VetCheckRequiredLimitInDays = 20;
        private readonly CrudService _crudService;

        public AnimalService(CrudService crudService)
        {
            _crudService = crudService;
        }

        public async Task UpdateVetCheckStatus()
        {
            var overdueDate = DateTime.Today.AddDays(-VetCheckOverdueLimitInDays);
            var requiredDate = DateTime.Today.AddDays(-VetCheckRequiredLimitInDays);

            await UpdateOverdue(overdueDate);
            await UpdateRequired(requiredDate, overdueDate);
        }

        private async Task UpdateOverdue(DateTime overdueDate)
        {
            var overdueAnimals = await _crudService.Get<Animal>()
                .Where(a => a.LastVetCheck < overdueDate && a.VetCheckStatus != VetCheckStatus.OVERDUE)
                .ToListAsync();
            overdueAnimals.ForEach(a => a.VetCheckStatus = VetCheckStatus.OVERDUE);
            await Update(overdueAnimals);
        }

        private async Task UpdateRequired(DateTime requiredDate, DateTime overdueDate)
        {
            var requiredAnimals = await _crudService.Get<Animal>()
                .Where(a => a.LastVetCheck == null
                            || (overdueDate < a.LastVetCheck && a.LastVetCheck < requiredDate && a.VetCheckStatus != VetCheckStatus.REQUIRED))
                .ToListAsync();
            requiredAnimals.ForEach(a => a.VetCheckStatus = VetCheckStatus.REQUIRED);
            await Update(requiredAnimals);
        }
    }
}

This example has been highly simplified for demonstration purposes. All services in C#Bot are guarded against C# Security which derives its security rule from the Security Diagram. Refer to Security in C#Bot for more details.

By default, C#Bot comes with many default service methods that you can elevate in your code. If you want to add custom code to have better control over your logic, refer to the Custom API Endpoint and Custom queries articles for more details.

And More

C#Bot has been designed to offer you maximum customisability. This article has briefly touched some of the most common functionality of the application, but every source file has been designed with protected regions.

For more advanced topics, see the following articles: