Skip to content

Library providing a way to define table model and to apply paging sorting and filtering operation server side.

License

Notifications You must be signed in to change notification settings

xaviersolau/TableModel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TableModel

Library providing a way to define table model and to apply paging sorting and filtering operation on server side.

Don't hesitate to post issues, pull requests on the project or to fork and improve the project.

Project dashboard

Build - CI Coverage Status License: MIT

Package Nuget.org Pre-release
SoloX.TableModel NuGet Beta NuGet Beta
SoloX.TableModel.Server NuGet Beta NuGet Beta

License and credits

BlazorLayout project is written by Xavier Solau. It's licensed under the MIT license.


Installation

You can checkout this Github repository or you can use the NuGet packages:

Install using the command line from the Package Manager:

Install-Package SoloX.TableModel -version 1.0.0-alpha.13
Install-Package SoloX.TableModel.Server -version 1.0.0-alpha.13

Install using the .Net CLI:

dotnet add package SoloX.TableModel --version 1.0.0-alpha.13
dotnet add package SoloX.TableModel.Server --version 1.0.0-alpha.13

Install editing your project file (csproj):

<PackageReference Include="SoloX.TableModel" Version="1.0.0-alpha.13" />
<PackageReference Include="SoloX.TableModel.Server" Version="1.0.0-alpha.13" />

Use case

Let's say that you write an application that needs to get some data from a server API. Usually you start thinking that you just need the load the data and to send it directly to the client. Then you realize that you gonna need to make a query with a filter on a given property but your boss is pushing you to deliver as soon as possible so you just add a Query strings and use it in your Entity Framework query through some custom methods in your repository. Finally, you end up with multiple query string and many custom methods to implement all specific requests.

Well, this is not really the best solution in terms of scalability and or maintainability. Don't you agree?

This project is here to help you in a very easy way to add an end-point that is going to serve your data and to be able to filter and/or sort your data. In addition, it's also going to help you to make partial data request if you don't need to load all data at once!

Another nice point is that from the client side this project will allow you to make data filter as easy as writing a lambda expression!

How to use it

Note that you can find code examples in this repository at this location: src/examples.

Create a shared Dto assembly

First of all, the Dto objects must be shared between the server and the client.

For instance if you want to use a WeatherForecastDto:

  • The server serving the data will need to have a reference on it to define the data mapping between the internal entities and the transmitted Dto.
  • The client requesting the data will need to have a reference on it to register the TableData and to use it. Thanks to Blazor this is also possible on web client side.

Set up the server

Add the Nuget

On the server API, you can add the SoloX.TableModel.Server Nuget. It provides all TableModel support and the controller base implementations.

Register services

In order to set up the TableModel services to serve table data, you just need to call the extension method AddTableModelServer from SoloX.TableModel.Server name space.

Here is a quick example to set up some data (in our case WeatherForecastDto) to serve from a custom table data WeatherForecastTableData.

services.AddTableModelServer(
    builder =>
    {
        // Here we are going to serve some data from a custom ITableData implementation.
        builder.UseQueryableTableData<WeatherForecastDto, WeatherForecastTableData>();
    });

Let's say that our WeatherForecastTableData will load our data from an Entity Framework DdContext WeatherForecastDbContext. All you need to do to write your WeatherForecastTableData is to define the mapping between your entity and your DTO.

For instance if we have an entity WeatherForecastEntity and a DTO WeatherForecastDto the TableData will look like this:

public class WeatherForecastTableData : AQueryableTableData<WeatherForecastDto>
{
    private readonly WeatherForecastDbContext dbContext;

    public WeatherForecastTableData(WeatherForecastDbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    protected override IQueryable<WeatherForecastDto> QueryData()
    {
        return this.dbContext.WeatherForecasts
            .Select(enity => new WeatherForecastDto()
            {
                /* Initialize all properties from the entity... */
            });
    }
}

Create the TableData Controller

Now that our TableData is initialized, we have to create the Controller that will actually serve the data through the server API end-point.

Once again it is really easy to make it because we just have to create a controller class based on the provided TableDataControllerBase implementation. You also have to declare the appropriate attributes to make your controller available through ASP.Net Core API stack.

/// <summary>
/// The TableDataController based on TableDataControllerBase that is providing the end-points to
/// query table data.
/// </summary>
/// <remarks>
/// You can also use the Authorization attributes here.
/// </remarks>
[Route("api/[controller]")]
[ApiController]
public class TableDataController : TableDataControllerBase
{
    /// <summary>
    /// Setup the TableDataController with the tableDataEndPointService provided in the
    /// SoloX.TableModel.Server package.
    /// </summary>
    /// <param name="tableStructureEndPointService">The end-point service that is actually doing the job.</param>
    public TableDataController(ITableDataEndPointService tableDataEndPointService)
        : base(tableDataEndPointService)
    {
    }
}

Basically this controller will provide 3 end-points:

Url path HTTP Method Summary Result
/api/TableData GET Get the list of table data available. The table data list.
​/api​/TableData​/{table data id}/data POST Post a data request. The requested data items.
​/api​/TableData​/{table data id}/count POST Post a data count request. The data count.

Create the TableStructure Controller

Coming soon...

Set up the client

Add the Nuget

On the client, you can add the SoloX.TableModel Nuget. It provides all TableModel support.

Register services

In order to set up the TableModel services to use the table data, you just need to call the extension method AddTableModel from SoloX.TableModel name space.

Here is a quick example to set up some data (in our case WeatherForecastDto) to be requested from the server.

In the Program.cs file form the Wasm Blazor client, you can register the TableModel services like this:

builder.services.AddTableModel(
    tableBuilder =>
    {
        tableBuilder.UseRemoteTableData<WeatherForecastDto>(
            config =>
            {
                config.HttpClient = new HttpClient
                {
                    BaseAddress = new Uri(builder.HostEnvironment.BaseAddress + "api/TableData/")
                };
            });
    });

Using the TableData

Whether or not we are in the server or the client project, the TableData can be used the same way.

Get TableData from ITableDataRepository

Once the table is registered in the services configuration, you just need to inject the ITableDataRepository. From this repository we can get a TableData instance associated to a given data type.

Note that creating a TableData instance does not actually load any data. The data will be loaded at query time.

Let's have a look at how we get a TableData instance with an example:

// Inject the TableDataRepository to get the registered TableData.
// It also can be injected as a constructor parameter.
[Inject]
public ITableDataRepository TableDataRepository { get; set; }

// Let's Load some data.
public async Task<IEnumerable<WeatherForecastDto>> LoadDataAsync()
{
    // Get the TableData associated to the type WeatherForecastDto from the TableDataRepository type.
    var weatherForecastTableDate = await TableDataRepository.GetTableDataAsync<WeatherForecastDto>();

    /// Then load data...
}

Basic queries

Now that we have got our TableData instance, we can make data queries to get the whole data or just a data page:

// First get data count from the TableData.
var dataCount = await weatherForecastTableDate.GetDataCountAsync();

// Get all data from the TableData.
var allData = await weatherForecastTableDate.GetDataAsync();

// But we may only need a data page from a given data index and page size.
var someDataPage = await weatherForecastTableDate.GetDataPageAsync(index, size);

Sorting data

If you need to get sorted data on a given property, thanks to the Lambda expression, it's really easy:

// Inject the ITableFactory to get a ITableSorting instance.
// It also can be injected as a constructor parameter.
[Inject]
public ITableFactory TableFactory { get; set; }

// Let's Load some sorted data.
public async Task<IEnumerable<WeatherForecastDto>> LoadSortedDataAsync(
    ITableData<WeatherForecastDto> weatherForecastTableDate)
{
    // Create the TableSorting.
    var tableSorting = TableFactory.CreateTableSorting<WeatherForecastDto>();

    // Register a sorting operation on TemperatureC property.
    tableSorting.Register(wf => wf.TemperatureC, SortingOrder.Ascending);

    // Run the query using the tableSorting.
    var sortedData = weatherForecastTableDate.GetDataAsync(tableSorting);
}

Filter data

Here again, it's easy to use lambda to setup the data filters:

// Inject the ITableFactory to get a ITableFilter instance.
// It also can be injected as a constructor parameter.
[Inject]
public ITableFactory TableFactory { get; set; }

// Let's Load some filtered data.
public async Task<IEnumerable<WeatherForecastDto>> LoadFilteredDataAsync(
    ITableData<WeatherForecastDto> weatherForecastTableDate)
{
    // Create the TableFilter.
    var tableFilter = TableFactory.CreateTableFilter<WeatherForecastDto>();

    // Register a filter operation on Summary property.
    tableFilter.Register(wf => wf.Summary, s => s.Contains("Hot"));

    // Run the query using the tableFilter.
    var filteredData = weatherForecastTableDate.GetDataAsync(tableFilter);
}

Note that there are limitations using lambda expression in filter: basically you will get the same limitation than the one you have in the underling queriable data implementation. For example if you are using EF Core behind the scene, you will have the same limitations.

In addition it is impossible in the current version to use EF.Functions in your filter expression.

About

Library providing a way to define table model and to apply paging sorting and filtering operation server side.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published