DotVVM v2.4.0 Release Notes

Release Date: 2019-12-28 // almost 3 years ago
  • Server side caching of view models (experimental)

    This feature can dramatically reduce data transferred between the server and the client.

    To enable this feature, add the following code snippet in DotvvmStartup.cs:

    config.ExperimentalFeatures.ServerSideViewModelCache.EnableForAllRoutes();
    

    When the feature is enabled, the viewmodels are cached on the server. When the client needs to do a postback, DotVVM can send only the diff of the viewmodel instead of serializing and transmitting the entire object. Thanks to this, we can save a lot of network traffic – almost 100% in extreme cases. Imagine a page with a GridView and a Delete button in every row – when you click on the button, the viewmodel on the client hasn’t changed at all. Thus the diff will be empty and the postback will transfer only a tiny JSON object with an identification of the button that was clicked – no viewmodel data at all. There were other ways to save this traffic, but this one is very convenient to use.

    🚦 The viewmodels are stored in memory by default, but the mechanism is extensible so you can use any storage you need – just implement the IViewModelServerStore interface. They are also deduplicated – we are using a hash of the viewmodel as a cache key, so when you use this feature on a public facing site which has the same “static” viewmodel for many users, the viewmodel will be kept in memory only once. And if the item is not in the cache any more, DotVVM will signal it to the client which will immediately issue a new postback with a full viewmodel.

    The feature can be enabled for all routes, or only for specific routes in the application. We recommend to enable it on less frequently used pages at first, and watch the memory consumption on the server – the cache should be cleaned up when the server gets low on memory, but still – we encourage to start using this feature carefully.

    We are still working on providing diagnostic tools that will help you identify how much this feature actually helped - how much traffic it saved and how much memory on the server it consumed.

    👀 see #704 for more info

    Public API is using C# 8 nullable reference

    ⬆️ Most of the DotVVM API is now annotated by C#8 nullable reference types. If you are already using this C# feature, this may create bunch of new warnings when you upgrade DotVVM, but we recommend you do that as it may reveal new issues. If you are not using it, we suggest you give it a try, we have already discovered few glitches in DotVVM caused by nulls :)

    Frozen config

    To prevent strange behavior the entire DotvvmConfiguration is now frozen at runtime - it can not be modified after DotVVM is initialized.

    Unfortunately, this may break some of your code if you have attempted to modify some option at runtime. On the bright side, it will fail early rather than running into race conditions (or what could happen).

    🔧 If you been modifying configuration just after the UseDotvvm function, you'll have to move the config modification into a lambda argument modifyConfiguration. For example, this works fine - the configuration is modified just before it gets frozen.

    app.UseDotVVM\<DotvvmStartup\>(..., modifyConfiguration: c =\> { c.RouteTable.Add(...); });
    

    #747

    Combining css classes

    🚀 When binding is assigned to both class attribute and Class-my-class property it used to behave in quite a strange way. With this release, the classes are combined.

    This will render a div with class="a b"

    \<div Class-a="{value: true}" class="{value: true ? 'a' : 'x'}" /\>
    

    👀 see #783 for more info

    Validation of grid view cells

    We have added properties to add validators to grid view cells (for the inline-edit mode). The validator can be added by setting the property ValidatorPlacement="AttachToControl" or ValidatorPlacement="Standalone" (or both when separated by comma). Validator placement AttachToControl will add the Validator.Value to the rendered input control, placement Standalone will place separate element after the input. To control what the validator does, you can place Validator.InvalidCssClass and similar properties to the GridView.

    ➕ Added InlineStylesheetResource

    💅 Like the InlineScriptResource, you can now add inline CSS (in the <style> tag) using the InlineStylesheetResource. Unlike the script, style is placed in the head, so be careful not to add styles when rendering the page.

    ItemValueBinding (and friends) must return primitive types

    We have decided to fix one design debt. Controls based on SelectorBase control (which is ComboBox, ListBox, and MultiSelect) have ItemValueBinding. You could put any value in ItemValueBinding - there was no validation and it caused unpredictable behavior. When the result of ItemValueBinding was primitive type everything was fine. When the result type was a complex type the behavior got strange and there is unfortunately no way how to guarantee consistent behavior. So we have added a validation that the result type is primitive to make sure everything works fine.

    "Primitive" in this case means anything that is not translated to object on client-side - which are numbers, string and enums.

    Redirects from static commands

    You can now safely use IDotvvmRequestContext.RedirectToUrl and IDotvvmRequestContext.RedirectToRoute from static commands. Note that you can get the IDotvvmRequestContext from the standard dependency injection.

    #757

    ⚠ API for runtime warnings

    👀 We have added infrastructure that will allow DotVVM to warn you at runtime when something suspicious happens. It will be reported to Asp.Net Core (that you'll probably see in the output of the server) and it will be propagated to JavaScript console.

    🚀 For example, it will warn you if you put something inside elements that must be self-closing in HTML. We will add more of these diagnostics in future releases. It is only enabled in debug mode.

    👀 see #750 for more details (the API is described there)

    💅 StyleBuilder.SetControlProperty polishing

    💅 The SetControlProperty method used to add new controls to properties using Server Side Styles got polished. It should now work correctly in all three mode (Overwrite, Append, Ignore) regardless if the target is a control collection, a template or a single control.

    You can for example add a postback handler to all buttons that satisfy some conditions:

    config.Styles .Register\<LinkButton\>(m =\> m.HasHtmlAttribute("data-hashandler")) .SetControlProperty\<ConfirmPostBackHandler\>(PostBack.HandlersProperty, s =\> s.SetProperty(c =\> c.Message, "you sure?"), StyleOverrideOptions.Append)
    

    You can also use SetHtmlControlProperty and SetLiteralControlProperty to easily create a html element or a simple literal.

    #737

    Deserialization on client

    🛠 @Mylan719 has rewritten one of the most feared piece of code in our code base - the dotvvm.serialization.deserialize that copies a JavaScript object into the view model and wraps everything with knockout observables. Number of bugs got fixed in it, if you have encountered a strange behavior especially with static commands, it should be gone.

    📇 Specifically, you can now copy object from one property to another using static commands {staticCommand: DataSet = FetchData(SelectedCategory); Metadata = DataSet.Metadata }.

    #772

    Binding may be specified without quotes

    Bindings in DotHTML files may be specified without the quotes around them (as you may be used to from React). This is now valid syntax:

    \<Button Click={command: MyMethod()} Text={value: MyLabel} /\>
    

    Just note that if you are also using Razor/MVC, don't get too much used to this, it behaves very strangely there.

    🛠 Bugfixes

    • RouteLink with binding in Query-something property now works as expected (#779)
    • 🛠 Redirect now works as expected when Dictionary<string, object> is used as query. This fixes some issues with LocalizablePresenter. (#777)
    • Error are propagated correctly (i.e. dotvvm.events.error is called) when network is unreachable (#770 #768)