Released DotVVM 4.0

Published: 3/22/2022 5:29:42 PM

We are happy to announce the release of DotVVM 4.0. This version contains several new features, many bug fixes and some significant performance improvements.

Also, we have tested this version internally on several large DotVVM projects, and we’ve experienced smooth upgrade experience with almost no breaking changes – it was much easier than upgrading from DotVVM 2.x to 3.0.


Simplified control development

One of the most requested features was a new way of building custom components. DotVVM offered two ways for building controls – markup controls and code-only controls. The markup controls were easy to use, but they had a lot of limitations. The code-only controls could do anything, but it was difficult to write them.

That’s why we introduced composite controls. These controls allow you to compose your own controls from the existing components quickly and in a nice “functional” way.

The only thing you need to do is to implement a method called GetContents which will return the desired hierarchy of components or HTML elements. We have also added several helper extension methods as well as a new type ValueOrBinding<T> which greatly simplifies handling properties that allow both data-binding expression or a “hard-coded” value.

Writing a control that can render an image and handle the click event is as simple as this:

public class ImageButton : CompositeControl
{
    public static DotvvmControl GetContents(
        [DefaultValue("Button")] ValueOrBinding<string> text,
        ICommandBinding click,
        string imageUrl = "/icons/default-image.png"
    )
    {
        return new LinkButton()
            .SetProperty(b => b.Click, click)
            .AppendChildren(
                new HtmlGenericControl("img")
                    .SetAttribute("src", imageUrl),
                new Literal()
                    .SetProperty(text)
            );
    }
}

Notice that we just use the LinkButton control with HtmlGenericControl (representing the img tag) and a Literal control inside.


Integrating React components

Another interesting feature we’ve added is the option to host third-party components in DotVVM pages and allowing them to bind to viewmodel properties or trigger commands.

In DotVVM 4.0, we’ve introduced the support for React, but the mechanism is generic so any front-end framework can be used in the future.

Using a JS module (a concept introduced in DotVVM 3.0), you can now expose React controls to DotVVM:

import { registerReactControl } from 'dotvvm-jscomponent-react';
import { YourReactComponent } from ...;

export default (context: any) => new MyModule(context);
class MyModule {
    constructor(context) {
        this.context = context;
    }
    ...

    $controls: {
        YourComponent: registerReactControl(YourReactComponent, { 
            this.context, // always pass the context to the component
            
            // specify default values for all parameters
            text = "default text",
            onClick() { /* do nothing when onClick is not set */ } 
        }),
        ...
    }
})

Then, you can use the control in the page like this:

@js MyModule

<js:YourReactComponent text={value: ButtonText} 
                       onClick={command: Clicked()} />


Performance and memory improvements

The new version of DotVVM contains several performance optimizations. We have changed many initialization tasks to work in parallel, and we have rewritten the view compiler so it doesn’t use Roslyn. Instead, it generates LINQ expressions.

This saves some memory, removes dependencies on Roslyn DLLs which are quite large, and finally, it is much faster.

We have also implemented special interning mechanism for strings as DotVVM filled the heap with many instances of the same string values.


Roslyn analyzers

We’ve written several Roslyn analyzers which help you to find common mistakes in your viewmodels. These analyzers detect whether the types in the viewmodel are serializable, and inform you with a wnarning if they find issues.

The analyzers are referenced directly from the DotVVM NuGet package so it should start working automatically.


Hot reload support

.NET 6 brought the Hot reload experience which allows you to some apply code changes without the need to restart your app. It can save a lot of time in the developer inner loop (change code – compile – wait until the app initializes – see the result).

DotVVM now detects that hot reload happened, and flushes some of its caches. When you add a property in the viewmodel, DotVVM should be able to notice it and reconstruct the viewmodel serialization maps, so when you reload the page, it should work without the need to restart the process.

Also, we have implemented the Hot reload experience for the DotHTML files. If you make any changes to a page, master page or a markup control, and save the file, it will be reloaded automatically, and DotVVM will also try to keep the state of the page.

We’ve learned to use this feature very quickly, and change both views and viewmodels while the application is running. There are of course many scenarios where the restart of the process is needed, but still it saves a lot of time.


Changes in the Authorize attribute

One change you’ll probably notice, is that the Authorize attibute was marked as obsolete. This may be a bit controversial step, but we encourage to change your application code to make the authorization explicit in the Init phase of the viewmodel, or in the command methods.

Doing the authorization using the attribute is not always intuitive – the attribute is enforced only then DotVVM calls the method or uses the viewmodel. When you call the method yourself, the attribute is not enforeced (and you may expect it to be enforced, which can be dangerous). Also, we’ve been dealing with the problem in static command services – if the service is registered as an interface and you put the attribute on the implementation, it will not get called.

Therefore, we recommend to call Context.Authorize() whenever you need to do the authorization. Most commonly, it will be in the Init phase of the viewmodel.

public class AdminViewModelBase : DotvvmViewModelBase
{

    public override async Task Init() 
    {
        await Context.Authorize();

        await base.Init();  // always call base.Init() - another authorization checks can be specified in the base page 
    }
}


Compilation status page doesn’t require separate NuGet package

We’ve moved the Compilation status page into the main DotVVM package.

You should uninstall the DotVVM.Diagnostics.StatusPage package – it is not needed any more.

Also, the URL of the status page has changed – now it is /_dotvvm/diagnostics/compilation


Summary

There are much more improvements and fixes in the framework. Don’t worry to upgrade – as mentioned before, we’ve updated the framework on many large DotVVM projects without almost any breaking change, and it was the smoothest experience in upgrade to a new major version so far.

We’ll be happy if you try the new version and give us feedback on our Gitter chat.

See the full list of changes in the Release notes.

Tomáš Herceg

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.


Subscribe to the newsletter!

Thank you for subscribing!


Social Sites


Popular