Preview 2 of DotVVM 5.0
Published: 5/5/2025 8:42:48 PMWe’ve been working on DotVVM 5.0 for quite a time, and we are thrilled to announce the release of public Preview 2 of DotVVM 5.0.
We have added a couple of new features, and made one significant change inside the framework – replaced Newtonsoft.Json with System.Text.Json, which should lead to better performance and lower memory usage.
Extensible GridViewDataSet
We published a blogpost about Extensible GridViewDataSet a few months ago. It allows you to implement your own class that inherits from GenericGridViewDataSet, and provide generic types describing the way how you want to do sorting, paging, and filtering. Thanks to this, you can easily work with token-based paging instead of page numbers, you can use multi-criteria sorting strategies, and more.
The feature also includes the new AppendableDataPager component, which enables you to implement “infinite” scrolling. It works with the same dataset paging API as the classic DataPager – it just appends the new page at the end instead of replacing the current one.
Server-rendered DataContext and DataSource
DotVVM has supported server-side rendering since its first versions. If you use the resource bindings or set RenderSettings.Mode=Server, the bindings are evaluated on the server and rendered into the resulting HTML page, as shown in the following example:
<!-- CLIENT-SIDE MODE -->
<h1>{{value: Title}}</h1>
<!-- resulting HTML - binding is tranlated to Knockout JS binding expression -->
<h1 data-bind="text: Title"></h1>
<!-- SERVER-SIDE MODE -->
<h1>{{resource: Title}}</h1>
<!-- resulting HTML - binding is evaluated and its value is emitted in the HTML-->
<h1>Public Preview of DotVVM 5.0</h1>
The server-side rendering is great for public-facing websites for being way friendlier to search engines – they do not need to evaluate JavaScript to access the page content. You can even exclude the Title property in the viewmodel on the client-side (for example by using [Bind(Direction.None)] ) to achieve smaller output HTML, if you don’t need to update the property value while the page is loaded.
However, if you wanted to render a list of items by using Repeater or GridView, there was a problem. Both components have supported server-side rendering and could output the individual items from the viewmodel collection. However, the collection itself must have been included in the viewmodel and sent to the client, resulting in the need to send some data twice.
<dot:Repeater DataSource="{value: BlogArticles}" RenderSettings.Mode="Server">
<article>
<h1>{{value: Title}}</h1>
<p>{{value: Abstract}}</p>
</article>
</dot:Repeater>
<!-- Rendered HTML -->
<article>
<h1>...</h1>
<p>...</p>
</article>
<article>
<h1>...</h1>
<p>...</p>
</article>
...
<!-- viewmodel included in the HTML page -->
..
"BlogArticles": [
{
"Title": "...",
"Abstract": "..."
},
{
"Title": "...",
"Abstract": "..."
},
...
]
...
This was because of a limitation we had in DotVVM since the first version – the hierarchy of DataContexts on the server must have corresponded to the hierarchy of binding contexts on the client. This is important for the translation of bindings to JavaScript, especially when you use _parent, _root, etc.
With DotVVM 5.0, we managed to lift this restriction, and you no longer need to include the collection in the viewmodel. This allows to significantly decrease the page size on public-facing sites.
<dot:Repeater DataSource="{resource: BlogArticles}">
<article>
<h1>{{resource: Title}}</h1>
<p>{{resource: Abstract}}</p>
</article>
</dot:Repeater>
<!-- Rendered HTML -->
<article>
<h1>...</h1>
<p>...</p>
</article>
<article>
<h1>...</h1>
<p>...</p>
</article>
<!-- viewmodel does not need to contain the BlogArticles collection at all -->
LoadFromQueryableAsync
DotVVM’s GridViewDataSet contained a handy method called LoadFromQueryble that let you easily fill the dataset from IQueryable, no matter which ORM you use.
However, this method was not asynchronous, and it was never easy to implement its async version, as every IQueryable provider has its own ToListAsync and CountAsync extension methods, there is no common interface in .NET that would implement these methods.
We decided to implement LoadFromQueryableAsync by using Reflection to find the concrete implementation of ToListAsync and CountAsync for commonly used ORMs and providers (currently, we have support for EF Core and EF 6, and want to add support for Marten). We’d love to hear your feedback on what library you use and love to be supported in DotVVM.
Replacing Newtonsoft.Json with System.Text.Json
The new .NET introduced the new System.Text.Json serializer, and it makes sense for DotVVM to use it. Although it may seem like an easy replacements, it was probably the most complicated pull request ever, as DotVVM implemented many custom JSON converters for various purposes, and the framework needs to do almost everything you can think of – we need to do JSON diffing, patching, encrypting or signing parts of the viewmodels, omit some properties (when they have ServerToClient or ClientToServer bind direction), and much more. We even had a custom mechanism for pre-compiling serialization maps.
However, DotVVM 5.0 managed to remove the dependency on Newtonsoft.Json, even on the .NET Framework (where you don’t have all the performance benefits of the new parser, but even though it is there). There may be breaking changes, especially if you manipulate with the client-side viewmodel using JavaScript and do not respect the server-side types exactly. The Newtonsoft.Json was more lax than System.Text.Json is, so things that used to work may stop working. Also, if you implemented your own JsonConverters, you will need to rewrite them as System.Text.Json converters.
Routing improvements in groups and localization
We introduces route localization in DotVVM 4.3, and found several gaps where it was not supported. DotVVM 5.0 adds localized route support for route groups and comes with the DotvvmRoutingRequestCultureProvider class that you can use to detect the culture from localized URL when using ASP.NET Core Request Localization feature.
We also changed several overloads of the Add method on the route table, and added several validation rules that prevent creating routes with meaningless combinations of arguments (for example, it was possible to create a route that used a custom presenter, but yet it could specify the path to the DotHTML file that was not used for anything). We also changed the nullability of some parameters, so the route name and URL are always required, while virtual path is not (as it is not used for presenter-based routes).
You may experience compile-time breaking changes, and the app might crash at startup if some of the routes uses an improper combination of arguments. However, this should be a one-time fix and it may uncover deeper problems in your route table.
Bootstrap, Business Pack & DotVVM Contrib
Together with the preview of DotVVM 5.0, we also published all component packages that will work with the new Preview 2 of DotVVM 5.0. Please note that all DotVVM packages should always have matching major and minor version numbers (e.g. everything is 4.3.* or everything is 5.0.*), otherwise you will be running into compatibility issues.
Feedback
Please try the preview of DotVVM 5.0 and let us know about the issues you found. Especially the Newtonsoft.Json replacement is a thing that may introduce many subtle breaking changes, and we’d like to catch all of them before we release the final version of DotVVM 5.0. All your feedback will be greatly appreciated.
We’ll be testing DotVVM 5.0 on our own projects in RIGANTI, and release the final version once we are sure it is reliable.

I am the CEO of RIGANTI, a small software development company located in Prague, Czech Republic.
I am Microsoft Most Valuable Professional and the founder of DotVVM project.