The road to DotVVM 2.0: Part 1 - REST API bindings

Published: 12/11/2017 12:54:26 PM

We will be releasing a beta version of DotVVM 2.0 in a few days. The implementation of all planned features is almost finished and now we are going to focus on testing and bug fixing.

 

In the first versions of DotVVM, the default way of building pages was using value and command bindings. From the beginning, we knew that there was the limitation of sending the entire viewmodel from the client to the server and back. Although DotVVM 1.x provided several options how to deal with this issue, it sometimes made the viewmodel heavy, especially on page which were not designed well from the UX perspective.

In a typical LOB page with a large form or a reasonably sized GridView, this approach is good enough and it provides a very easy way to develop this kind of UI experience. Hovewer, if the page contains four GridViews with thousands of rows, there are dozens of modal dialogs with nested GridViews, the the command binding starts being very problemmatic and you need to do a lot of optimizations to make the application work shoothly.

In DotVVM 1.x, we have the Bind attribute that can be used to specify which parts of the viewmodel should be transferred in each direction. There is also the static command binding that allows to call a method on the server and update a property in the viewmodel with the result of this method without the need to transfer the viewmodel at all.

 

That’s why DotVVM 2.0 will bring several new features which addresses the issue with heavy viewmodels.

If you’d like to see all the new features we are planning, see our roadmap.

 

REST API Bindings

What if a GridView contents is not a part of the viewmodel? What if it can be just loaded from a REST API and the viewmodel can be used only to handle filtering, paging and sorting? That’s exactly what REST API bindings in DotVVM 2.0 can do.

1. Add the Microsoft.AspNetCore.Mvc package in the project and create a controller which returns a list of objects:

[HttpGet]
public List<ProductDTO> GetProducts([Microsoft.AspNetCore.Mvc.FromQuery]SortingOptions sort)
{
    return context.Products.Select(p => new ProductDTO()
        {
            Id = p.ProductId,
            Name = p.ProductName,
            SupplierName = p.Supplier.CompanyName,
            CategoryName = p.Category.CategoryName,
            …
        })
        .ApplySortingOptions(sort)
        .ToList();
}

 

2. Install Swashbuckle.AspNetCore package and configure Swagger JSON (and optionally Swagger UI):

// ConfigureServices()
services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new Info() { Title = "Northwind API", Version = "v1" });
});

// Configure()
app.UseSwagger();
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Northwind API");
});

 

3. Run the following command line script in the web application directory:

dotnet dotvvm api create http://localhost:43852/swagger/v1/swagger.json DotVVM2.Demo.RestApi.Api Api/ApiClient.cs wwwroot/Scripts/ApiClient.ts

This will download the Swagger JSON file and generate C# and TypeScript clients at the specified paths.

 

4. Register the API client in your DotvvmStartup.cs file. This will give you the _api variable you can use in your binding expressions to access the REST APIs.

config.RegisterApiClient(typeof(Api.Client), "http://localhost:43852/", "/Scripts/ApiClient.js", "_api");

 

5. Use the API to fill the GridView:

<dot:GridView DataSource="{value: _api.ApiProductsGet(Sort.SortDescending, Sort.SortExpression)}" SortChanged="{command: SortChanged}">
    <dot:GridViewTextColumn HeaderText="Id" ValueBinding="{value: Id}" />
    <dot:GridViewTextColumn HeaderText="Product Name" ValueBinding="{value: Name}" />
    <dot:GridViewTextColumn HeaderText="Supplier" ValueBinding="{value: SupplierName}" />
    <dot:GridViewTextColumn HeaderText="Category" ValueBinding="{value: CategoryName}" />
    …
</dot:GridView>

 

6. Store the sorting parameters in the viewmodel:

public SortingOptions Sort { get; set; } = new SortingOptions()
{
    SortExpression = nameof(ProductDTO.Id)
};

public void SortChanged(string expression)
{
    if (Sort.SortExpression == expression)
    {
        Sort.SortDescending = !Sort.SortDescending;
    }
    else
    {
        Sort.SortExpression = expression;
    }
}

 

You can also call POST, PUT or DELETE actions in your API e.g. on a button click. If you send these commands to the same URL as your GET is, it will get refreshed automatically. And there is much more to the REST API bindings.

 


Next time, we’ll dig in the Static Command Services - a mechanism that allows to consume server-side methods directly from the views. This makes the static command bindings much more powerful.

Tomáš Herceg

I am the CEO of RIGANTI, small software development company located in Prague, Czech Republic.

I am a Microsoft Regional Director and Microsoft Most Valuable Professional.

I am the author of DotVVM, an open source .NET-based web framework which lets you build Line-of-Business applications easily and without writing thousands lines of Javascript code.