ServiceStack: business logic that depends on the database itself

Viewed 55

I'm exploring ServiceStack and I'm not sure what is the best way to implement some business logic.

Using the "Bookings CRUD" example I would like to enforce the following rule:

  • a given Booking can only be saved (either created or updated) if the hotel has enough free rooms for the particular dates of that booking

Please note that I'm not asking how to calculate "free rooms".

What I'm asking is, from the architectural point of view, how should this be done.

For example, one way would be:

  • create a request DTO to query the number of configured rooms (lets call it "QueryRooms")
  • use the existing "QueryBookings" to query current bookings present in database
  • create a " : Service" class to customize the Booking Service, in order to intercept the "CreateBooking" and "UpdateBooking" requests
  • inside the custom methods for "CreateBooking" and "UpdateBooking", somehow get the results of "QueryRooms" and "QueryBookings", check if there are enough free rooms for the current request, and proceed only if so

This doesn't look very clean, because the service "CreateBooking" and "UpdateBooking" would depend of "QueryRooms" and "QueryBookings".

What would be an elegant and effcient solution, using ServiceStatck?

1 Answers

You can override AutoQuery CRUD operations with your own Service implementation using the AutoQuery DTO.

Where you can use the Service Gateway to call existing Services which you can use to perform any additional validation & modify the request DTO before executing the AutoQuery operation to implement the API, e.g:

public class MyCrudServices : Service
{
    public IAutoQueryDb AutoQuery { get; set; }

    public object Post(CreateBooking request)
    {
        var response = Gateway.Send(new QueryRooms
        {
            From = request.BookingStartDate,
            To = request.BookingEndDate,
        });
        if (response.Results.Count == 0)
            throw new Exception("No rooms available during those dates");

        request.RoomNumber = response.Results[0].Id;
        return AutoQuery.Create(request, base.Request);
    }
}

Note: calling in-process Services with the Service Gateway is efficient as it calls the C# method implementation directly, i.e. without incurring any HTTP overhead.

Related