Releases: riganti/dotvvm
DotVVM 2.4 Preview 1
Support for ASP.NET Core 3.0
We have handled the breaking change in Microsoft.AspNetCore.Authorization
between 2.2
and 3.0
, and tested the framework extensively on ASP.NET Core 3.0.
DotVVM is now fully suported (and tested) on:
- OWIN and .NET Framework 4.5.1
- ASP.NET Core 2.1 (LTS - Long-term Supported release)
- ASP.NET Core 3.0 (latest release)
Our plan is to always support the LTS releases and the last stable release of ASP.NET Core.
If you are still on ASP.NET Core 2.0, upgrade soon as the minimum supported version of ASP.NET Core will be changed to 2.1 in the future.
New MultiSelect
control
DotVVM now support basic MultiSelect
control. The API is basically the same as you know from ComboBox
, except you have a SelectedValues
property. Usage is like this:
<dot:MultiSelect SelectedValues="{value: SelectedValues}"
DataSource="{value: Values}"
SelectionChanged="{command: OnSelectionChanged()}"
ItemValueBinding="{value: _this}"
ItemTitleBinding="{value: _this}"
ItemTextBinding="{value: _this}" />
Default presenter can be specified on route groups
When creating a route group, you can now use overload DotvvmRouteTable.AddGroup(string groupName, string urlPrefix, string virtualPathPrefix, Action<DotvvmRouteTable> content, Func<IServiceProvider, IDotvvmPresenter> presenterFactory)
, which allows you to specify a default IDotvvmPresenter.
With this change, you can for example specify that the routes should respect locale in the route parameter "Lang" by LocalizablePresenter.BasedOnParameter("Lang")
:
routes.AddGroup("MyGroup", "", "", table => {
table.Add("{Lang}/Route1", "something", "something.dothtml");
}, LocalizablePresenter.BasedOnParameter("Lang"))
Note that the presenter don't compose, it's not a middleware. So this route will only accept the Lang2
query parameter and always ignore the Lang1
.
routes.AddGroup("MyGroup", "", "", table => {
table.Add("Route1", "something", "something.dothtml", LocalizablePresenter.BasedOnQuery("Lang2"));
}, LocalizablePresenter.BasedOnQuery("Lang1"))
(see #753)
4096 commits
We have passed the virtual line of having 4096 merged in master branch. It does not mean anything in practise, fortunately git will still work and nothing else can be affected. So we used the very important "anniversary" to at least fix some typos 61ee3fd
Methods invoked in sequence can be async
When you make a (static) command like this: DoAsync(); Do2Async()
, DotVVM automatically waits for both of these methods to finish. If you'd need to extract the resulting value of the Task<T>
s, you can use the Result
property - {staticCommand: Property = MyMethod().Result}
.
UpdateProgress can attach to particular concurrency queues (#720)
<dot:UpdateProgress
control has got properties IncludedQueues
and ExcludedQueues
which control where the update is triggered. For example, if you have a separate queue for background requests, you don't want to display any info about it:
<dot:UpdateHandler ExcludedQueues="refreshOneGrid, refreshSecondGrid:" />
ValidationErrorFactory supports local variables (#734)
When you create validation error paths using ValidationErrorFactory.CreateModelError
or ValidationErrorFactory.CreateValidationResult
from a Linq.Expression, you can also reference local variables and it will just propagate the resulting value from them. It's mostly useful for handling array indices:
var index = SomeIndex;
this.AddModelError(a => a.List[index].MyProperty, "It's wrong.");
TextBox UpdateTextAfterKeydown changed to UpdateTextOnInput
The UpdateTextAfterKeydown
property was marked as obsolete. It was using the keypress
event which didn't work on mobile devices and in other scenarios. The framework now uses oninput
event for the same purpose.
There is also a new event called TextInput
which triggers in this case. Be careful not to trigger postbacks which transmit huge viewmodels - we encourage you to use static command with this event.
Design-Time Error Checking in CheckBox, RadioButton and ComboBox
We have added error checking for various controls that contain combination of properties whose data-binding types must match. The controls didn't work properly and sometimes their behavior was unpredictable when the types were different.
<dot:CheckBox CheckedItems="{value: _parent.SelectedIds}" CheckedValue="{value: Id}" />
The framework now checks that CheckedValue
binding type is T
and SelectedIds
type is IEnumerable<T>
(or IEnumerable<Nullable<T>>
). Similar rules apply to RadioButton
and ComboBox
.
We recommend to use Diagnostics Status Page and check that all pages in your application use these controls correctly.
CSRF token is lazy loaded (experimental)
The CSRF token can be loaded after the page is displayed.
- When the config option CsrfTokenLazyLoading is enabled, CSRF token is not rendered by default and will be requested before the first postback. This removes one source of non-determinism and may allow easier caching of entire DotVVM pages.
- In any case, when the CSRF token or Session ID is invalid (for any reason), the server returns that as a JSON error message, the client automatically asks for a new token and retries the postback.
To enable this feature, you must enable it in DotvvmConfiguration.ExperimentalFeatures.LazyCsrfToken
:
config.ExperimentalFeatures.LazyCsrfToken.EnableForRoutes("AdminPage", "AnotherPage")
// or
config.ExperimentalFeatures.LazyCsrfToken.EnableForAllRoutes()
Allowed strange chars in attribute names (#727)
It should be now OK to use square []
and round ()
brackets in attribute names, for example <span [text]="..." />
. It may help when working with some client-side templating.
Improved performance of ValidationSummary (#734)
We have redesigned a bit how the client-side validation works. The errors are not stored in a knockout observable anymore, changes in validation errors can be observed using the validationErrorsChanged
event. If you have been using validationErrors
directly, you'll have to adjust it's usage as it's not ko.observable
anymore.
Debugging and diagnostics improvements
- Error page now has Binding tab which displays information about the binding that caused the exception (if the exception is related to some binding).
- Error page crashed when some object could not be serialized.
- #700 - In Debug mode, resources in the HTML are preceded by a comment that says the name, type and location type of the resource.
- #728 - Resource with primary location being local cannot have have fallbacks.
- Improved error handling in some edge cases (6ec553e, 6d9543b).
Other fixes
- #701 - Fixed missing condition on file age in DeleteOldFiles (community contribution - thanks to @ppech).
- #714 - Circular dependencies in resources are now detected
- #740 - The promise returned by a static command is now rejected, when error occurs.
- #721 - We now culture specific globalize.js resource in case you use
ToString
in a binding. - #732 - Fixed SetValue in nested markup control.
- #725 - LinkButton does not use
href="#"
. - #698 - Fixed server-rendered Repeater (and friend controls) when the DataContext is swapped entirely.
- #731 - Resolved FormatException that occurred under strange circumstances.
- #738 - Removed suppression of errors in style attribute unless value binding is rendered.
- #742 - GetValue does not end up in an infinite cycle when custom binding is used.
- #743 -
HandleAsImmutableObjectInDotvvmProperty
attribute added to indicate shared objects for server-side styles. Validation.Enabled
property was restricted to not allow value bindings.
DotVVM 2.3
New Features
- The
context.ReturnFile
method can now specify theContent-Disposition
header. Until now, the header was alwaysattachment
. - Added
context.LocalRedirect
method which checks whether the specified URL is local. We strongly recommend using this method on all places where the user can inject his own URL to redirect - e.g.Account/Login?returnUrl=something
GridViewDataSet
methods that apply sorting and paging operations onIQueryable
were made public to allow writing theLoadFromQueryableAsync
extension method. See #688.- Added infrastructure for rendering
script[type=html]
templates. This will be useful for control developers using the Knockout template binding, especially DotVVM Business Pack.
Fixes
- Fixed error in
IncludedInPage
property when the resource binding was used. - Validation errors collection was not cleared when some parts of the viewmodel were set to
null
or reinitialized with new objectS. The validator binding handlerupdate
method was not used at all. Validator.InvalidCssClass
functionality didn't work properly for multiple CSS classes and didn't remove all classes in some situations.- Fixed XSS vulnerability in registration of DotVVM polyfill resources.
Breaking changes
- CheckBox was rendering different HTML structure for the case when the text was empty. This structure did not include the
label
element, that is in most cases used as a base element for restyling of the checkbox design. Now, thelabel
element is rendered in both cases.
DotVVM 2.2
TL;DR; There are some new minor features. The most important point is Validation - EnforceClientFormat, which may break some existing code if it is using DateTime
or nullable numberic type in view model.
New features
Binding Cache
We have added caching interface IDotvvmCacheAdapter
that provides access to built-in caching mechanism on Asp.Net Core or OWIN that reflect memory usage on your server.
ValueBindingExpression.CreateThisBinding
is now cached, so it's invocation should be quite cheap.
When you want to create binding at runtime you can now use a helper method DotvvmBindingCacheHelper.CreateCachedBinding
that makes sure that the binding is not recreated every time. Creation of bindings is usually time-consuming, so it should not be done on every request. (more info in PRs #672 and #664)
By the way, we have also (hopefully) improved the error messages when something fails with binding. When an error page is displayed for a binding-related exception, there is a new tab Binding that shows some information about the binding (data context, type, ...). Let us know what you think about that and what could be improved.
Validation
ValidationErrorFactory.CreateValidationResult<T>(ValidationContext validationContext, ...)
Overload that does not require explicitDotvvmConfiguration
Session cookies are SameSite
This was sometimes the case before. It means that postbacks won't work in third-party iframe
s (so your application should be safe from clickjacking).
Fixes
Validation - EnforceClientFormat
This part is a fix and unfortunately a breaking change at the same time. In older versions, DotVVM did not validate that DateTime and numeric fields were valid on the client-side and sent null to the server in that case. It could be enabled by EnforceClientFormatAttribute
, but nobody really did. It is now by default enabled on nullable numeric types, DateTime, and DateTime?, so it enables validation in cases where it was disabled previously. While this has a potential to "fix" existing code as not validating the input is likely a bug, it may also break some code that relied on that behavior. Please make sure that all your views using nullable DateTime and numerics work as expected. (more info in PR #666)
For example, suppose you had a dot:TextBox
bound to a property of type int?
. The problem is that when you paste value like "asd"
, it will write a null value into the property because "asd"
is not a valid numeric value. The solution for this problem was applying EnforceClientFormatAttribute
to the property in your view model. Now, you don't have to do that anymore. If you use that attribute somewhere, you can safely remove it.
Repeater control initialization
We have change a bit how the Repeater initialization works. Controls with templates have to initialize the control tree before it is used by command invocation and HTML rendering and when this initialization is dependent on data from view model, it has to be done twice on postbacks - once before command invocation and then before rendering since the command may have changed the data. In older version Repeater have not done that in all cases, because it's quite time-consuming. Unfortunately, in some cases, it broke some code, so we are now re-initializing it two times, but only in case the data is actually changed. (more info in #653)
Unique id generation for nested trees
If you were creating controls at runtime, you may know that before adding more child controls into the newly create control has to be added to the control tree. The reason was, that the mechanism that generates unique ID (for control command and Postback.Update
) did not work correctly when entire subtree was added at once. From this version, this should work correctly, so you can initialize entire subtrees at once. (more info in #668)
dot:RouteLink
in Events.Click
container
It should now get precedence over the Events.Click
handler. (more info in #630)
DotvvmAuthenticationHelper.ApplyRedirectResponse
Fixed in DotVVM 2.2.0.2
When you installed Microsoft.Extensions.DependencyInjection
2.1.0 or higher in your application and used DotvvmAuthenticationHelper.ApplyRedirectResponse
, this method was throwing an exception with a message that ServiceProvider had been disposed.
netstandard assembly loading on .NET Framework 4.7.1+
Fixed in DotVVM 2.2.0.2
DotVVM View compilation on .NET471+ was not able to load netstandard assembly.
DotVVM 2.1
New features
- Improved server-side rendering for
Repeater
andGridView
controls - Enhancements in Server-Side Styles (for example adding postback handlers to controls)
ValidationErrorFactory.CreateValidationResult
now doesn't requireDotvvmConfiguration
- REST API client generator generates meaningful C# class name for the API client
Perf improvements
- Performance tweaks in
HtmlWriter
andDataItemContainer
Repeater
performance improved using memoization to prevent frequent rebuilding of control treeHtmlWriter
performance improvements- Control properties collection uses perfect hashing to improve performance
Bug fixes
- Fixed
IncludeInPage
rendering - Fixed
_index
variable issues in controls with server rendering - Fixed HTTP response on invalid HTTP method
- Client-side validation errors are cleared before a new object is validated
- Fixed dependency injection into markup controls
- Fixed array access JavaScript translation
- Fixed generating of unique IDs for
GridView
sort commands - Fixed number formatting for zero values
- Fixed
_api.RefreshOnChange(..., Prop1 + Prop2)
which allows watching for multiple properties - Fixed bug with resource bindings in markup controls
- Fixed serialization of control property values in markup controls
- REST API bindings - API URL can be parameterized from the code
- Fixed null assignments for complex types in static commands
DotVVM 2.0.3
New features
- Default ControlRegistrationStrategy now includes subfolders
- Prohibited hardcoded values on DataContext
EmailAddress
attribute now supports client-side validation
Bug fixes
- Fixed bug in dotvvm.events.unsubscribe
- Fixed number formatting bug with zero values
- Fixed data-binding issue of hard-coded values into markup controls
- Fixed invoking generic methods from static commands
- Fixed data context handling for some GridViewColumn properties
- Fixed null reference exception in detection of data context changes
- Fixed byte array serialization
DotVVM 2.0.2
New features
- Support of Microsoft.Extensions.DependencyInjection v2.0
- Guid operations can be used in value bindings - for example
GuidProp != Guid.Empty ? GuidProp.ToString() : ''
- Added
SuppressPostBackHandler
which can disable command on a particular control - Improved translation of arguments in postback handlers
- Routes in Route Groups can have empty virtual path
- Script resources preloading
Bug fixes
- Error page is displayed in debug mode on error from static commands
- Fixed disabling of postbacks for
LinkButton
control in some browsers - Fixed issue with view compilation on .NET 4.5.2 and newer
- Fixed serialization of negative long numbers
- Fixed rendering of
ContentTemplate
insideGridView
columns - Fixed resolving properties from inner classes in resource binding
- Fixed bug with using
ITemplate
in markup controls
DotVVM 2.0.0
Main new features
- REST API Bindings - DotVVM allows interacting with REST APIs directly from the DOTHTML views
- Static Command Services - is a feature which allows injecting of a C# class in the page using
@service
directive and calling its methods using Static Command Binding. - PostBack Concurrency Modes
_collection
Context Variable- New Binding System - mostly internal change but really huge.
- Postback Handlers infrastructure rewritten
Upgrading from DotVVM 1.0 to DotVVM 2.0
See migration guidelines: https://www.dotvvm.com/docs/tutorials/how-to-start-upgrade-to-2-0/2.0
To review all changes, please see preview releases of DotVVM 2.0.
DotVVM 2.0.0-preview02-final
Breaking changes
DotVVM Registration
Signature of registration methods was changed. The reason is to be able safely execute registration of dotvvm services in compiler.
We introduced new interface called IDotvvmServiceConfigurator
. This interface includes method void ConfigureServices(IDotvvmServiceCollection services)
. This method should includes all registrations of services needed for runtime of dotvvm. This part of code is called from compiler really often.
Warning: Avoid to init Entity Framework, calling API, sending emails and similar actions. Method void ConfigureServices(IDotvvmServiceCollection services)
is meant only for registration of DotVVM
OWIN
The parameter IDotvvmOptions options
was removed from signature of app.UseDotVVM()
method. This functionality was moved to IDotvvmServiceConfigurator
. You can simply implement IDotvvmServiceConfigurator
interface on your DotvvmStartup.cs or you can create another class. If your DotvvmStartup implements this interface then a generic parameter TDotvvmStartup from app.UseDotVVM<TDotvvmStartup>()
internally casts the DotvvmStartup as IDotvvmServiceConfigurator
.
We introduced new overload app.UseDotVVM<TDotvvmStartup, TDotvvmServiceConfigurator>()
in case you want to implement IDotvvmServiceConfigurator
to separated class.
AspNet Core
The same change as for OWIN was made on function IServiceCollection AddDotVVM<TServiceConfigurator>
.
The IDotvvmOptions options
parameter was removed and replaced by generic type that expects implementation of IDotvvmServiceConfigurator.
DotvvmConfiguration
Debug property can be modified only in IDotvvmStartup and registration method app.UseDotVVM()
. When you try to modify Debug property after initialization it throws exception.
Resources
Removed jQuery resource
In an effort to make DotVVM less depended we have removed jQuery resource. If you need it simply add jquery to you project and register in DotVVM configuration config.Resources.Register("jquery", new ScriptResource() { ... }
.
Routes
Method config.RouteTable.Add()
contained parameter type of Func<IDotvvmPresenter>
. This signature of the parameter was change to Func<IServiceProvider, IDotvvmPresenter>
. Now we provide an instance of IServiceProvider in factory method.
Some of Javascript API changes
dotvvm.postBackHandlers
was renamed todotvvm.postbackHandlers
DotVVM 2.0.0-beta01
Binding Properties
see Binding System Refactoring #341
- Better Javascript translator
- In the ViewModelSerializationMap it's possible to rename properties for client-side and JavascriptTranslator will translate it correctly, use
Bind(Name = "MyName")
attribute - Null checks in binding were previously done by
try ... catch
, which also caught exception inside called functions. Now it is done by real checks, so inner exceptions are propagated correctly - Binding can be transferred from one control to another in different data context and they will still evaluate and translate to JS correctly
- This means that you can use inherited properties to transfer dependencies into your markup control even though they are deeply nested
- You can even use MarkupControls recursively, just make sure they are server-rendered
- Super cool extensibility
- Extension parameters like
_collection
,_index
and_api
are just a tip of the icebergs ;)
- Extension parameters like
- Bindings have ResultType property accessible at runtime
- Controls have DataContextType property accessible at runtime
- Command Binding IDs are "more" unique and less readable
Function Arguments in Bindings
All bindings now have an implicit conversion to a delegate - essentialy, when the expected type is a delegate, the binding is wrapped in lambda. In Javascript it's represented as a function. And when the delegate contains any parameters, these get registered as additional symbols to the parser. For example to set (a) => a + 1
into a property of type Func<int, int>
you can use {value: arg + 1}
To use the parameters with staticCommand you can set the commandArgs symbolic parameter (the same way you'd do with command binding)
REST API
DotVVM allows interacting with REST APIs directly from the DOTHTML views. You can fill GridView, Repeater and other controls with data from the REST API, and use Button or other controls to call REST API methods as a response to user action. It is also possible to refresh data that have already been loaded (in the GridView for example) based on a change of a particular viewmodel property, or explicitly.
See: https://www.dotvvm.com/docs/tutorials/basics-rest-api-bindings/2.0
Model state helpers
You can just viewModel.AddModelError(v => v.MyObject.PartOfTheForm.Property3, "It's invalid")
instead of creating JS evaluatable string path
Controls improvements
- ComboBox.ItemValueBinding and ItemTextBinding - use them instead of ValueMember and DisplayMember
- TextBox.ValueType is obsolete, it's infered from result type of
Text
property
string.Format in value bindings
string.Format
method is correctly translated to Javascript. You can also use [primitive type].ToString("Format")
method - this one is also two-way, so it's possible to use it instead of FormatString
property on TextBox.
Route Groups
see #363
you can register routes in groups with specified path and id prefixed to prevent repetitive literals and help with visual code orientation:
routes.AddGroup(name: "Admin", prefix: "admin", virtualPath: "Views/Administration", content: adminRoutes =>
{
// adminRoutes is of type RouteTable
adminRoutes.Add("Users", "users", "Users.dothtml"); // name = Admin_Users, path = "admin/users", virtualPath = "Views/Administration/Users.dothtml"
adminRoutes.Add("Articles", "articles", "Articles.dothtml");
});
Dependency Injection into controls
It works in two modes:
- Simple/intuitive/automatic/hipster mode - when the control does not have a parameterless constructor, it is initialized from the default IServiceProvider. It is used mainly for infrastructure controls that need to get some dotvvm service, for non-control DotvvmBindableObjects that need or on Asp.NET Core projects that use the default DependencyInjection properly.
- Explicit/enterprise mode - when the control is marked by [RequireDependencyInjection] it is created using resolver registered in the default IServiceProvider. You can use it if you want services from your separate container or need some weird injection features, like property injection
Dependency Injection into dothtml views
You can require a service using @service
directive. It is mainly useful for Asp.Net Core ILocalizer interface and for calling static commands. The service usage can't be translated to Javascript, so usage in value binding will throw an exception.
@service myService = IMyService<string>
{{resource: myService.SomeProperty}}
{{command: myService.DoSomething()}}
Markup controls packed into dlls
Markup file loaded supports embedded://...assembly name/...name of the resource
syntax for referencing embedded resources from view or markup control registration. It should allow you to pack dotcontrol
files into the dll and distrube them in a library. The files are referenced as the original source code and have to be compiled in the target project, so you can apply compile-time styles to them.
IncludeInPage
property
Just a wrapper for knockout if
binding handler.
FormControls.Enabled
property
Added a FormControls.Enabled attached property which disables controls inside that are not explicitly enabled.
Controls affected
- in DotVVM - Button (ButtonBase), CheckBox (CheckableControlBase), ComboBox (SelectorBase), DataPager, LinkButton (ButtonBase), ListBox (SelectorBase), RadioButton (CheckableControlBase), TextBox
- in Bootstrap - Button, CheckBox, DataPager, RadioButton, TextBoxGroup
- in Business pack - Button, Calendar, CheckBox, CheckBoxList, ColorPicker, ComboBox, DataPager, DateTimePicker, DateTimeRangerPicker, DropDownList, MultiSelect, NumericUpDown, RadioButton, RadioButtonList, RangeCalendar, RangeSlider, Rating, Slider, TextBox
Example
<div FormControls.Enabled="{value: false}">
<dot:Button Text="I am disabled" />
<dot:Button Text="I am enabled" Enabled="{value: true}" />
</div>
dot:BodyResourceLinks
and dot:HeadResourceLinks
When you use one of these controls in page, the resources will be render in location that is defined by the control. Only the first control on the page is activated to prevent accidential multiple times included scripts.
LocalizablePresenter
It's a utility for easy localization based on query string or route parameters. It just sets the Thread
s
current culture.
// based on query string parameter lang, `myPage?lang=cs-CZ` will be in czech culture
config.RouteTable.Add("myRoute", "myPage", "myPage.dothtml", presenterFactory: LocalizablePresenter.BasedOnQuery("lang"));
// based on parameter lang, `cs-CZ/myPage` will be in czech culture
config.RouteTable.Add("myRoute", "{lang}/myPage", "myPage.dothtml", presenterFactory: LocalizablePresenter.BasedOnParameter("lang"));
By default, it redirects to a default culture when a invalid code is specified, you can disable that using redirectWhenNotFound
parameter.
see #513
Custom constuctor for serializer
On a IViewModelSerializationMapper
, you can set your own method to create a new instance of the viewmodel.
mapper.Map(m => {
// create from Asp.Net DI
m.AllowDependencyInjection();
// custom constructor
m.SetConstructor(serviceProvider => SomehowCreateViewModel(serviceProvider))l
});
Ben.Demystify for the error page
By default, the error page uses Ben.Demystify
library to show nicer stack traces.
Implemented CSS style bindable
Added Style-*
property group that generates the style
knockout binding. I'm not sure what type should I use for the property group, currently there is object
.
Usage example:
<div Style-color="{value: Color}" Style-display="{value: Condition ? 'none' : 'inline-block'}"/>
<div style="background-color: green;" Style-width="{value: Width + 'px'}"/>
see #572
DotVVM 1.1.8
Fixes
- Validation errors are cleared before SPA navigation starts
- ViewModel and dependencies are disposed in finally block.
- Fixed route url parser with optional parameter at start of url