-
Notifications
You must be signed in to change notification settings - Fork 24
Creating a ASP.NET Core Backend
The common way to create a NubeSync backend is via a ASP.NET Core WebApi site, although other hosting options would be possible (such as a single process, ASP.NET classic etc.)
This documentation is focused on an ASP.NET Core site using a Microsoft SQL database for storage and assumes that you already have a ASP.NET Core WebApi project with a working database connection. If you're having trouble setting this up, see the docs: https://dotnet.microsoft.com/apps/aspnet
You can download the complete source code for this sample here:
https://github.com/stefffdev/NubeSync/tree/master/samples/Backend/NubeSync.Service
When using the NubeSync framework the client tracks all changes made to the database as operations, which are then pushed to the server, where they are processed to update the database.
- Install the NubeSync.Server nuget package into your project.
- Register the NubeSync OperationService in the ConfigureServices method in the file Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<IOperationService>(s => new OperationService(typeof(TodoItem)));
}Every type that you want to sync has to be registered with the OperationService, this makes the sync process faster since it uses less reflection.
- Add a table for the operations in your DbContext:
public DbSet<NubeServerOperation> Operations { get; set; }That is necessary because the server stores every client operations for resolving sync conflicts.
The DTO (Data Transfer Object) is a class that represents the data you want to sync to the clients.
- Create a file TodoItem.cs in your project and derive it from NubeTable:
public class TodoItem : NubeServerTable
{
public string Name { get; set; }
public bool IsChecked { get; set; }
}- Add a table for our TodoItem in your DbContext:
public DbSet<TodoItem> TodoItems { get; set; }- Create the migrations for the added table and apply them to your database by running the following commands:
dotnet ef migrations add Initial
dotnet ef database update
- Create a new file OperationsController.cs in the Controllers folder
- Add the following usings to the file:
using NubeSync.Core;
using NubeSync.Server;
using NubeSync.Server.Data;- Change the class to:
[ApiController]
[Route("[controller]")]
public class OperationsController : ControllerBase
{
private readonly DataContext _context;
private readonly IOperationService _operationService;
public OperationsController(
DataContext context,
IOperationService operationService)
{
_context = context;
_operationService = operationService;
}
[HttpPost]
public async Task<IActionResult> PostOperationsAsync(List<NubeOperation> operations)
{
try
{
await _operationService.ProcessOperationsAsync(_context, operations);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
return Ok();
}
}What that code does is read all operations the client posted and updates the database accordingly. All this is done inside a transaction, which means that either all posted operations succeed or all operations fail. This is so that not only some changes get applied, or even worse only modified operations get applied, but not the initial add operation of this record.
Clients should not only push their changes to the server, but also receive all items that have changed since the last sync.
- Create a new file TodoItemsController.cs in the Controllers folder
- Change the class to:
[ApiController]
[Route("[controller]")]
public class TodoItemsController : ControllerBase
{
private readonly DataContext _context;
public TodoItemsController(DataContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetItems(DateTimeOffset? laterThan)
{
var tableName = typeof(TodoItem).Name;
if (laterThan.HasValue)
{
return await _context.TodoItems.Where(i => i.ServerUpdatedAt >= laterThan).ToListAsync();
}
else
{
return await _context.TodoItems.Where(i => !i.DeletedAt.HasValue).ToListAsync();
}
}
}All we do here is return the items that have a ServerUpdatedAt timestamp later than the timestamp the client sent. This is necessary to implement an incremental sync where the client only receives records that were changed since the last sync. If the client does not include a timestamp in the request all records are returned.
That is all that has to be done at the server side.