The Vidyano.Core NuGet package is a powerful tool designed for developers who want to connect to their Vidyano applications using C#.
Available on , it offers seamless access for creating custom integrations or performing unit tests, ensuring enhanced functionality and reliability in your applications.
Ensure you are using version 3.19.0 or later of Web3 to take advantage of the new feature that allows setting any Iconify icon as an icon for a custom action. Access the full list of icons at , and use the set:name format for specifying icons in your custom actions.
In the Management you can go to the Custom Action and enter the set:name of the icon you want to use. For example material-symbols:verified-user-outline for an Check user action.
Vidyano has the ability to enable verbose logging. This will log all requests including details about the user (user name, ip address, user agent, client version, …), the incoming data and outgoing data. This can help for troubleshooting request or for auditing purposes.
Custom Vars Example
As a developer you can also set 5 custom variables per request to make it easier to search for specific request or easily see something without having to open the incoming or outgoing data.
// Check the user's language at the moment of the request
Manager.Current.SetLogCustomVar(1, Manager.Current.UserLanguage);
// Check the user's culture info at the moment of the request
Manager.Current.SetLogCustomVar(2, Manager.Current.UserCulture);
// Check the weekday at the moment of the request
Manager.Current.SetLogCustomVar(5, Manager.Current.Today.DayOfWeek.ToString());
RequestId Example
On the client side we can also set a request id that can be used as correlation id to follow different request in a single brower session or on a specific computer. You can use the AppServiceHook.createData method to set a requestId on the data.
Grids
These screenshots are from older versions, some minor UI changes can be expected
The query grid is a powerful data table component with the following features:
Big data
Users can quickly scroll over a million lines of data. While in practice this would make for a time consuming job, other features such as filtering will make it easy to find relevant data. Developers however do not need to worry about the size of the data set as data is loaded and rendered in a performance and memory efficient way.
Lazy loading
Data set chunks are loaded whenever they should be visible within the visible boundaries of the screen. This means that even if your entire data set would potentially return over a million records but your screen can only show 30 or so at the time, the grid will load a chunk of data (by default in pages of 100 records).
Data sorting
Out of the box sorting of data on any column or multiple columns by holding the CTRL-key and clicking each column in order of sorting priority.
Pin columns
Keep columns in view while horizontally scrolling over your data. This view-state is automatically persisted on their profile.
Hide columns
Users are in control over the amount of data they want on the screen. This view-state is automatically persisted on their profile.
Reorder columns
Users are in control over which columns should be visible first. This view-state is automatically persisted on their profile.
Filtering
Easily filter data by clicking on the column filter icon and enter custom filter text or select one or more items from the list with the distinct values for that column in the data set.
Users can choose to save the filter for later use:
Built for performance
The grid component uses cutting edge techniques to ensure that the user experience feels lightning fast. For example, the grid reuses DOM elements in order to keep the memory footprint as small as possible while taking advantage of hardware accelerated rendering.
Manage column order, visibility and pinning
Enter search text or select a value from the list
Saved filter that only shows products with color red
Migrating from v5.x
If you still have a Vidyano project running on .NET 4.8 and ASP.NET you can find steps here to migrate to the latest version running on ASP.NET Core.
The latest Vidyano project template will enable this by default, otherwise there are a few things that need to be added to the .csproj to provide enough context for it to work.
Disclaimer
Use of SourceGenerators depend on available content.
Analyzers and CodeFixes are available in any project.
Some Patterns are not supported by Analyzers at the moment:
When Clause on Switch Expression / Statements
Generators
Actions Generator
BusinessRules Generator
Context Generator
CustomAction Generator
Generated Constant classes
All generated Constant classes are available under {RootNamespace}.Service.Generated namespace.
BusinessRuleNames
PersistentObjectTypes
PersistentObjectAttributeNames
Dependency Injection
By using the InitializeByCtor attribute on a field, the source generator will inject this field via the generated constructor.
The Attribute can only be applied when no constructor is provided.
Attribute is available via reference Vidyano.Abstractions.
Index Generator
Generate an overview index by adding the GenerateIndex attribute to an entity.
This will result in the following being generated:
A partial {Entity} class with a QueryType attribute.
A partial {VEntity} QueryType class.
A partial {Entities}_Overview
Creating an Index for an Entity
Adding this GenerateIndexattribute creates an overview index.
To change the name of the Index, pass the desired type as an argument. Note: Include a namespace if you want the index to be generated under a different namespace.
To change the name of the QueryType, use the QueryType attribute.
Important Notes:
Index will not be generated if QueryType or Index is already added manually, except if they are partial.
If the QueryType contains audit fields, the appropriate interface will be applied. This can differ from the Entity if you add IgnoreForIndex to an audit field.
Additional Attributes
You can add several attributes to the entity's properties to control the index:
Search: Adding this attribute creates a second {Property}_Sort property to allow full search on this property.
Note: This is only needed when values can contain spaces.
IgnoreForIndex: This property will not be included in the index.
Projects
Main project
Additional Files & Global Usings
Add following ItemGroup to the .csproj project file.
External Context
If the context file does not exist in the main project, you can use the appsettings.json file as an alternative, as the context will be read from there.
Library project
Missing App_Data json files warning
When incorporating SourceGenerators into a library project, you may encounter a VIDYANO0010 warning indicating missing App_Data JSON files. This warning is not applicable to library projects, as they do not utilize App_Data.
To bypass this warning, two methods are available.
By disabling the Model SourceGenerator via local .editorconfig file
By ignore the warning via csproj file
Exceptions
When using EmitCompilerGeneratedFiles in .csproj project file you can get exceptions when compiling in Windows because of use of long filenames.
To fix this issue you need to add the following registration key (Reboot needed to take effect)
Backwards Compatibility
For backwards compatibility we created an Obsolete PersitentObjectTypes class (old version). The only thing you need todo when upgrading to the new source generator is changing the using in de .csproj project file by adding the Generated.Obsolete namespace.
This way the project wil run as before.
Note: If you add the new usings directly you can use de CodeFix to update to the correct code.
Reports
The reports feature offers developers the capability to securely expose data queries in various formats such as XML, JSON, and CSV. This ensures that data can be accessed externally while maintaining security through authentication and tokenization.
Token
Reports make use of a secure random (384bit) token to access the specified query. This token should be kept private and not shared with anyone as they will be able to access the report with it.
Index Generator
Model Generator
ProjectTargetType Generator
ProgramUnitNames
ProgramUnitItemsNames
QueryNames
QuerySources
ActionNames
Languages
MessageKeys and Messages
AppRoles
WebsiteNames
Obsolete.PersistentObjectTypes
Index class.
A V{Entities} property on the Context if it does not already exist.
Only the IId interface will be copied to the QueryType.
IndexReference: You can include a property from the Reference in the index by adding one attribute per property and defining the path on the reference. This can be more than one level deep.
Note:
If the Reference is Nullable, then every generated IndexReference property is also Nullable.
Path cannot contains a Collection property.
Migration scripts for v5 Repository database
Make sure you have a backup before running the scripts
public partial class CompanyActions
{
[InitializeByCtor]
private readonly IMyService myService;
}
[GenerateIndex]
public partial class Customer
{
public string Id {get; set;}
[Search]
public string Name {get; set;}
[IgnoreForIndex]
public string Private {get; set;}
[IndexReference(nameof(Person.Name), Search = true)]
[IndexReference("Address.CityName")]
[Reference(typeof(Person)]
public string Person {get; set;}
}
-- Logs
if COL_LENGTH('Vidyano.Logs', 'ExternalId') is null
begin
exec sp_rename 'Vidyano.Logs.Id', 'ExternalId', 'COLUMN';
alter table Vidyano.Logs add Id bigint identity
alter table Vidyano.Logs alter column Type tinyint not null
alter table Vidyano.Logs alter column CreatedOn datetimeoffset(3) not null
alter table Vidyano.Logs drop constraint [PK_Vidyano_Logs]
alter table Vidyano.Logs add constraint PK_Logs primary key(Id)
CREATE UNIQUE NONCLUSTERED INDEX [AK_Logs] ON [Vidyano].[Logs] ([ExternalId])
--CREATE NONCLUSTERED INDEX [IX_Logs_PERF1] ON [Vidyano].[Logs] ([CreatedOn] DESC)
end
-- Settings
if COL_LENGTH('Vidyano.Settings', 'Id') is not null
begin
declare @keyLength int = COL_LENGTH('Vidyano.Settings', 'Key')
if @keyLength = -1 or @keyLength > 255
begin
alter table Vidyano.Settings alter column [Key] nvarchar(255) not null
end
alter table Vidyano.Settings drop constraint [PK_Settings]
alter table Vidyano.Settings drop column [Id]
alter table Vidyano.Settings add constraint [PK_Settings] primary key ([Key])
end
-- Users/UserGroup/Users_Group
SET ANSI_PADDING ON
IF (OBJECT_ID('[Vidyano].[Groups]', N'U') is null)
BEGIN
-- Move Groups to separate table
select u.[Id], u.[Name], u.IsSystem, u.CreationDate, g.TwoFactorRequired
into [Vidyano].[Groups]
from [Vidyano].Users u
inner join [Vidyano].[Users_Group] g on g.[Id] = u.[Id]
alter table [Vidyano].[Groups] add constraint [PK_Groups] primary key ([Id])
alter table [Vidyano].[Groups] add constraint [UQ_Groups_Name] UNIQUE NONCLUSTERED ([Name])
-- Switch to Groups table
ALTER TABLE [Vidyano].[UserGroup] DROP CONSTRAINT [FK_UserGroup_Group]
ALTER TABLE [Vidyano].[UserGroup] WITH CHECK ADD CONSTRAINT [FK_UserGroup_Group] FOREIGN KEY([Groups_Id]) REFERENCES [Vidyano].[Groups] ([Id])
ALTER TABLE [Vidyano].[UserGroup] CHECK CONSTRAINT [FK_UserGroup_Group]
END
go
if COL_LENGTH('Vidyano.Users', 'IsSystem') is not null
begin
alter table Vidyano.Users drop column IsSystem
end
go
if COL_LENGTH('Vidyano.Users', 'IsEnabled') is null
begin
alter table Vidyano.Users add
IsEnabled bit constraint DF_Users_IsEnabled default 1 not null
,TwoFactorToken varchar(100) null
,ResetPasswordNextLogin bit constraint DF_Users_ResetPasswordNextLogin default 0 not null
declare @constraint nvarchar(256)
select @constraint=d.name from sys.tables t
inner join sys.schemas s ON s.schema_id = t.schema_id
inner join sys.default_constraints d on d.parent_object_id = t.object_id
inner join sys.columns c on c.object_id = t.object_id
and c.column_id = d.parent_column_id
where
t.name = N'Users'
and s.name = N'Vidyano'
and c.name = N'Version'
IF LEN(ISNULL(@constraint, '')) <> 0
BEGIN
DECLARE @sqlcmd VARCHAR(MAX)
SET @sqlcmd = 'ALTER TABLE [Vidyano].[Users] DROP CONSTRAINT' + QUOTENAME(@constraint);
EXEC (@sqlcmd);
END
alter table Vidyano.Users alter column Version varchar(100) not null
exec ('update [Vidyano].[Users] set
IsEnabled = case when JSON_VALUE(Profile, ''$.Disabled'') = ''true'' then 0 else 1 end
, TwoFactorToken = JSON_VALUE(Profile, ''$.TwoFactorToken'')
, ResetPasswordNextLogin = case when JSON_VALUE(Profile, ''$.ResetPasswordNextLogin'') = ''true'' then 1 else 0 end
, Profile = JSON_MODIFY(JSON_MODIFY(JSON_MODIFY(Profile, ''$.Disabled'', NULL), ''$.TwoFactorToken'', NULL), ''$.ResetPasswordNextLogin'', NULL)
from Vidyano.Users
where Profile is not null')
end
go
declare @keyLength int = COL_LENGTH('Vidyano.Users', 'Language')
if @keyLength = -1 or @keyLength > 10
begin
update [Vidyano].[Users] set [Language] = '' where [Language] is null
alter table [Vidyano].[Users] alter column [Language] varchar(10) not null
end
set @keyLength = COL_LENGTH('Vidyano.Users', 'CultureInfo')
if @keyLength = -1 or @keyLength > 10
begin
update [Vidyano].[Users] set [CultureInfo] = '' where [CultureInfo] is null
alter table [Vidyano].[Users] alter column [CultureInfo] varchar(10) not null
end
go
IF (OBJECT_ID('[Vidyano].[UserSettings]', N'U') is null)
BEGIN
exec('select Id, [Settings]
into [Vidyano].[UserSettings]
from [Vidyano].Users
where len([Settings]) > 2')
alter table [Vidyano].[UserSettings] add constraint PK_UserSettings primary key (Id)
alter table [Vidyano].[UserSettings] alter column [Settings] nvarchar(max) not null
alter table [Vidyano].[UserSettings] add constraint [FK_UserSettings_Users]
foreign key ([Id])
references [Vidyano].[Users] ([Id])
on delete cascade on update no action;
alter table [Vidyano].Users drop column [Settings]
end
go
IF (OBJECT_ID('[Vidyano].[UserProfiles]', N'U') is null)
BEGIN
exec('select Id, [Profile]
into [Vidyano].[UserProfiles]
from [Vidyano].Users
where len([Profile]) > 2')
alter table [Vidyano].[UserProfiles] add constraint PK_UserProfiles primary key (Id)
alter table [Vidyano].[UserProfiles] alter column [Profile] nvarchar(max) not null
alter table [Vidyano].[UserProfiles] add constraint [FK_UserProfiles_Users]
foreign key ([Id])
references [Vidyano].[Users] ([Id])
on delete cascade on update no action;
alter table [Vidyano].Users drop column [Profile]
end
-- ClientCodeSnippets (was used in v1 web client)
drop table if exists Vidyano.ClientCodeSnippets
-- Group flattening (groups are no longer member of another group)
IF (OBJECT_ID('[Vidyano].[TmpGroupGroups]', N'U') is null)
BEGIN
exec('select Users_Id, Groups_Id
into Vidyano.TmpGroupGroups
from Vidyano.UserGroup where Users_Id in (select Id from Vidyano.Groups)');
END
-- Drop old inherited Users_Group table
drop table if exists [Vidyano].[Users_Group]
-- Delete groups from Vidyano.Users
delete from Vidyano.UserGroup where Users_Id in (select Id from Vidyano.Groups)
delete from Vidyano.Users where Id in (select Id from Vidyano.Groups)
-- Flatten groups
;WITH cte AS (
SELECT tmp.[Users_Id]
,ug.Name GroupName
,tmp.[Groups_Id]
,gg.Name MemberOf
FROM [Vidyano].[TmpGroupGroups] tmp
inner join Vidyano.Groups ug on ug.Id = tmp.Users_Id
inner join Vidyano.Groups gg on gg.Id = tmp.Groups_Id
union all
SELECT cte.[Users_Id]
,cte.GroupName
,tmp.Groups_Id
,gg.Name MemberOf
FROM [Vidyano].[TmpGroupGroups] tmp
inner join cte on cte.Groups_Id = tmp.[Users_Id]
inner join Vidyano.Groups gg on gg.Id = tmp.Groups_Id
)
insert into Vidyano.UserGroup (Users_Id, Groups_Id)
select distinct ug.Users_Id, cte.Groups_Id
from Vidyano.UserGroup ug
inner join cte on cte.Users_Id = ug.Groups_Id
except
select ug.Users_Id, ug.Groups_Id from Vidyano.UserGroup ug
-- Update repository version
update Vidyano.Settings set Value='61' where [Key]='RepositoryVersion'
Access
Depending on the sensitivity of the data you can use 3 options to access a report.
AuthorizationHeader (Recommended): This method uses the Authorization header to pass the token. The main benefit is that the token won’t be accidentally exposed in places where the request url is logged (i.e. diagnostics).
(Best security): This method needs custom code to generate a HMAC256 signature for the requested resource. The benefits are that the key is never send across the wire and that the request can’t be replayed at a later time.
You can configure the minimum access level that should be used on a report. When it is accessed using a lesser secure option it will be flagged as compromised and it will not be available unless a new token has been generated.
Format
Reports return XML by default. You can use the format query parameter or Accept header to request the data as json (application/json), csv (text/csv) or tsv (text/tab-separated-values).
This option expects the token to be passed as Authorization header using the Bearer scheme when accessing the report.
curl
JavaScript
PowerShell
AuthorizationSignature
The signature is generated by including a Date header (containing a RFC1123 formatted UTC date and time), an Accept header (containing application/json, text/xml, text/csv or text/tab-separated-values) and using HMAC256 to sign the combination of the request url, accept and timestamp using a newline separator with the token as key. The Date header will be validated that it is no more than 5 minutes in the past or future (to allow for some clock skewing).
.NET
PowerShell
Postman
For testing you can also use Postman as it allows for Pre-request scripts and variables:
Compromised
When a report is accessed using a less secure option than configured or using http instead of https it will be flagged as compromised. A log entry will be written with information about the requested url, ip and user-agent.
You can re-enable the report by giving it a new token. On a production deployment the patching feature can be used to regenerate the token.
Excel
Reports can be used to import data in an Excel file. The data will be linked to the Excel table so that it can be refreshed manually or automatically when the file is opened.
This can be done by starting the From Web wizard in Excel:
In the wizard you can switch to Advanced mode where you can add the Authorization header:
Paging / Sorting
Using top and/or skip also requires sorting to provide consistent results.
For the AuthorizationSignature option you’ll need to include the whole url as requested (which shouldn’t contain the token and format in that case, the format should be in the Accept header) for the signature calculation.
Filtering
You can use the $filter query parameter to include the text-search (as used inside a Vidyano application in the search box on a query) that should be used to filter.
For the AuthorizationSignature option you’ll need to include the whole url as requested (which shouldn’t contain the token and format in that case, the format should be in the Accept header) for the signature calculation.
Migrating an existing Vidyano v5 project
Because Vidyano v6 uses ASP.NET Core and EntityFrameworkCore most migrating steps are related to this (and any online tutorial for upgrading to ASP.NET Core will help in this step). Below are the general steps needed to get you up and running.
Create a new project using the above steps (this will create a correct project for .NET core and the correct startup logic)
As with most tutorials, it is now time to copy over the existing code you had (.NET core no longer has the path of different files inside your .csproj file so you can just copy them over folder wise)
Service goes to Service folder, static webrelated files for to wwwroot, App_Data goes to wwwroot/App_Data
A few exceptions are needed, for the *Advanced/*AuthenticatorService/*BusinessRules/*Queries/*Web it is best to copy the methods/properties/fields in the existing classes where possible
Any existing NuGet references that the application had will need to be added again (as PackageReference, the packages.json is no longer valid)
Any appSettings/connectionStrings from web.config need to be copied over in the appsettings.json file, Vidyano.X settings go inside the Vidyano object (<add key="Vidyano.X" value="True" /> becomes {"Vidyano":{"X": true}})
Vidyano v6 (and .NET Core/ASP .NET Core) makes great use of DI, that's why all PersistentObjectActions implementation now require a default constructor that at least excepts the TContext as a parameter, other services can now be constructor injected there as well.
Your existing EntityFramework DbContext needs to be upgraded to EntityFrameworkCore. Some notable/recommended changes
Make sure properties are virtual (the Proxy package is included but needs to be enabled manually)
Mark InverseProperties where needed
You existing *Web also needs some updates, ASP.NET Core no longer uses HttpResponseMessage so all custom api methods needs to be updated to use IActionResult as return type (that exact type).
*Advanced also has most breaking changes (deprecated code has been dropped, ...)
Architecture
Groups / Rights
Functionality is driven by giving groups (application roles) specific rights to actions (e.g. Save, New, Delete, Print, Export, …). Without an explicit right for an action the user won’t be able to execute the action and the backend will throw an exception.
Query, Read, Edit and New rights can be defined at the attribute (property/column) level, all other actions can be defined at the persistent object (class/table) level.
Authentication
Vidyano application can be configured to allow multiple authentication sources which all map to users that can be assigned to groups.
Vidyano Authentication
Enabled by default, allows the usage of any custom name and password to log in. Passwords are stored in the database using a BCrypt hash. The BCrypt complexity can be configured and is increased by the framework on regular intervals (currently at 13). Will require a password with at least a length of 8 and it should not be in the blacklist (currently a list of the top 25 worst passwords and Pwned Passwords using the V2 range API), can be configured to use a different length, complexity (no longer recommended) or a different blacklist.
Password requirements are based on and
The service is used to validate that passwords don’t appear on any leaked password list. The new V2 api is used with the Range API to provide k-anonymity to check for breached password without disclosing the actual password (or even a full hash of it).
ADFS Authentication
Allows the use of an Active Directory Federation Service to authenticate the user in the application. The application can be configured to automatically put unknown authenticated users in specific group or this logic can be handled using code (to put the user in a specific group based on the returned claims). Will use the http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname claim as user name.
OAuth Authentication Providers
Allows the use of an OAuth provider (Microsoft, Google, Facebook, Twitter or Yammer) to authenticate the user in the application. Can also be configured to automatically create unknown users. Will use the email as user name.
Auth Token\
Once the user has been authenticated the server will return an auth token to the client that can be used for the next requests.
The token is a SHA256 hash composed of the following information:
Application salt
User name
User version (incremental number in the database that is increased when the password is changed or the user is disabled)
The actual IP address to check can be configured to allow switching between addresses within a specific cidr range in case the users have multiple external IP address or it can be changed using code.
Security Token
To ensure that the client works with the correct model (based on the rights) the server will generate a security token that can be checked when the persistent object is send back.
The token is a SHA256 hash composed using the following code:
The token uses a random salt to prevent any oracle attacks. All information is included so that the client can only modify the entity as it was sent by the server with only the attributes that were available. For attributes that the user has no edit rights the actual value is also used in the token so that the application can securely set these attributes on the server-side. Trying to modify any of the data will result in an exception being thrown by the backend.
\
Force Https / TLS 1.2
Vidyano will automatically redirect to https:// for certain subdomains (azurewebsites.net, apphb.com, …) and can be configured with a simple appSetting for custom domains. Enabling this flag will also enable HSTS (Strict Transport Security) which tells the browser to always go the https:// site directly even if the user tries to go to http:// to block MITM attacks.
Depending on the deployment it is recommended to only allow TLS 1.2 if possible. This can be enabled for Microsoft Azure App Services on the SSL settings tab:
Two-factor authentication
Each user can set its own two-factor code on the user settings page (available using the gear in the lower left of the application). The application can also be configured to require (force) two-factor authentication for users that are in a specific group (e.g. Administrators).\
var token = "YOUR_TOKEN_HERE"; // It's recommended to get this from a setting/vault/configuration/...
var reportUrl = "https://localhost:44332/GetReport/4cb4854ca87a4e4aaf66c8f2469d58ea";
var accept = "application/json";
var date = System.DateTime.UtcNow;
var timestamp = date.ToString("R", System.Globalization.CultureInfo.InvariantCulture);
var messageSignature = string.Join("\n", reportUrl, accept, timestamp);
string signature;
using (var hmac = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(token)))
signature = Convert.ToBase64String(hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(messageSignature)));
var request = System.Net.WebRequest.CreateHttp(reportUrl);
request.Accept = accept;
request.Date = date;
request.Headers.Add("Authorization", "Bearer " + signature);
// Pre-request Script
var token = pm.environment.get("token");
var reportUrl = request.url;
var accept = "application/json";
var timestamp = (new Date()).toGMTString();
var messageSignature = [reportUrl, accept, timestamp].join("\n");
var signature = CryptoJS.HmacSHA256(messageSignature, token).toString(CryptoJS.enc.Base64);
pm.globals.set("accept", accept);
pm.globals.set("timestamp", timestamp);
pm.globals.set("encrypted_signature", "Bearer " + signature);
Mark ForeignKey where needed
Mark classes with Table attribute
Remove Index attribute (needs to be configured in OnModelCreating)
Managing User Secrets
During development it is recommended to store connection strings, salts, or other secrets in a secure manner. It is best to avoid storing these secrets in the code or local configuration files.
Vidyano has the ability to set any Query as Global Search which allows the end users to use a simple text search in the menu that will search through all the queries and shows those queries that returned results (or errors). This has given us an easy way to provide this kind of functionality to users.
The only problem has always been performance, the application will launch a full text search for all columns on all the queries that are defined as global search so the total time to give results has always been in the 1-10 seconds range.
Instant search has been written from the ground up with performance as the number one priority.
Example
Instant search is implemented as an advanced feature, it is up to the developer to keep the total processing time as low as possible (recommended <100ms).
Which will give the following experience to the end user, as seen on
Azure AD SAML based Sign-on
Vidyano can be configured to use Azure AD as an authentication provider. In combination with the SCIM feature to provision the users and groups you could use the Azure AD to completely control your users outside the application.
Configuration
You’ll need to set the Single Sign-on Mode to SAML-based Sign-on.
For the URLs you should use the url of the application for Identifier and followed by Authenticate/SAML2 as Reply URL:
The Configure button at the bottom will give your the correct settings (SSO Service Url and Base64 Certificate) that you need to use on the Security page.\
Vidyano Documentation
This documentation will help you build powerful data-driven applications using the Vidyano application platform.
Getting started Section
For developers ready to dive in, the Getting Started section provides the necessary steps to install tools and create a new project with Vidyano.
Documentation Sections
The provides insights into the various concepts within a Vidyano project. It details their functionalities and guides on how to effectively utilize them in your applications. Developers can leverage this knowledge to enhance their projects and maximize the platform's potential.
Current versions
Here are a few badges with the latest versions of various packages used for Vidyano projects
SCIM 2.0 Service Provider
The SCIM standard was created to simplify user management in the cloud by defining a schema for representing users and groups and a REST API for all the necessary CRUD operations. See spec
Example
To enable the SCIM end-point Vidyano will require an authenticated request, the passed bearer token will need to be checked in the AuthenticatorService class. The easiest way would be to provide a single custom setting that contains the token so that it can be checked.
public override bool CheckScimCredentials(ScimCredentials credentials)
{
var setting = Manager.Current.GetSetting("ScimBearerToken");
return !string.IsNullOrEmpty(setting) && setting == credentials.Token;
}
Other scenarios could be created by storing multiple tokens in the database.
Azure AD
Azure can be configured to sync the AD users with your Vidyano application:
Tenant URL is the url of the application (e.g. for the demo application the tenant url is https://demo.vidyano.com/ )
For the mapping we recommended the following settings:
Groups
Users
public override string GetClientIpAddress(string userName, string ipAddress)
{
if (userName == "salesguy") // NOTE: Always on the road
return Manager.Current.GetUser(userName).Profile["AuthTokenSalt"];
return base.GetClientIpAddress(userName, ipAddress);
}
private string GetTamperingDetectionToken(string securityToken)
{
string salt;
if (securityToken == null)
salt = ObjectEx.GetSecureRandomString(6);
else
salt = securityToken.Substring(1, 8);
var allData = new StringBuilder();
allData.AppendLine(salt);
var poSalt = VidyanoDbCache.Default.GetPersistentObject(Id, false)?.Salt;
if (poSalt != null)
allData.AppendLine(poSalt);
allData.AppendLine(Id.ToString());
allData.AppendLine(ObjectId);
if (BulkObjectIds != null)
BulkObjectIds.Run(id => allData.AppendLine(id));
Attributes.OrderBy(a => a.Id).Run(attr =>
{
allData.AppendLine(attr.Id.ToString());
if (attr.IsReadOnly && !attr.Name.Contains("."))
{
var attrWithReference = attr as PersistentObjectAttributeWithReference;
allData.AppendLine(attrWithReference != null ? attrWithReference.ObjectId : attr.Value);
allData.Append(attr.IsValueChanged);
allData.AppendLine();
}
});
allData.AppendLine(SecurityScope.ApplicationSalt);
var result = allData.ToString().GetSHA256();
return "$" + salt + result;
}
Use DI for creating PersistentObjectActions objects
Extra DI changes
Updated group actions for DI
Configuration
Added VidyanoConfiguration
Create random salts/token on startup if needed
Allow extra data on JWT token
Schema Synchronization
Finalized EF Core schema synchronizer
Added schema synchronizer for non-EF model
Fixes
Fixed GetDiagnostics/Api not working
Fixed invalid initial schema SQL
Fixed issue with invalid PK type for Vidyano.Logs
Maintenance
Removed License PO
Working RavenDB implementation
Added EntityFrameworkCore logging
Only create new ServiceScope if needed
March 2020
New Features
Service Worker
Added service worker support
Better offline capabilities
Value Objects/ViewModels
Added ValueObject/ViewModel attribute
Better data modeling support
Nullable Reference Types
WIP #nullable support throughout codebase
Better null safety
In-Memory Logging
Added InMemoryLogProvider
Removed DisableLogs
Fixes
Fixed index.html for Chrome80
Fixed issue with not being able to search on computed displayattribute
Fixed obfuscation issues
Maintenance
Set up CI with Azure Pipelines
Removed dependency on IObjectContextAdapter
Expose GetTextSearchExpressionForXXColumn helpers
February 2020
New Features
Exception Handling
Tweaked exception handling for /Authenticate calls
Better error handling
Fixes
Handle failed loaded cache for WebControllerLogger
January 2020
New Features
Advanced Search
Tweaked Advanced Search Save/Load functionality
Better search capabilities
Fixes
Fixed issue when searching ref attr with missing breadcrumb columns
Fixed issue with AdvancedSearch ExportToExcel not working
Maintenance
Trim userName input for GetCredentialType
Updated copyright year to 2020
Note: 2020 was a major refactoring year with the complete overhaul of the repository provider system, introduction of RavenDB support, and migration to .NET 5.0. Many breaking changes were introduced to support provider abstraction.
Changelog 2022
December 2022
New Features
Configuration Enhancements
Added ShowAppInformation config option
Added UseRichLogs config for enhanced logging
Added more IVidyanoConfiguration comments for better documentation
User Rights Management
Added OnlyGroupRights feature (#348)
Better control over permission inheritance
Fixes
Fixed issue when setting lazy loaded references to null
Fixed IUpdateableLog.Append/Prepend adding extra newlines (RavenDB)
Fixed some issues when AsDetail is used on virtual PO
Maintenance
Dropped .NET Core 3.1 support (end of life)
Updated packages including Newtonsoft.Json security update
Repeating jobs improvements
November 2022
New Features
.NET 7 Support (#351)
Added .NET 7.0 support
Take advantage of latest framework improvements
Mail Improvements
Enhanced mail functionality
Better email handling
User Management
Added IUser.ToggleGroup for easier group management
Diagnostics
Added application/json support for /diagnostics (#352, #354)
Developer Experience
Inform administrator when application had errors or warnings at startup
Show extra developer information on PO in management
Fixes
Fixed issue with User/NullableUser not showing for Guid/Guid? properties
Fixed issue when GetCollectionName returns null (RavenDB)
Fixed text search issue when label was also used as referenced property
Maintenance
Add dummy services for mocking/console apps
Proxy tweaks, trust localhost by default
RavenDB: Profiler shows when request was from cache
October 2022
New Features
API Enhancements
Allow IAsyncEnumerable<> API methods
Async streaming support for APIs
Query Features
Added QueryResultItem.GetOriginalValue
Better access to original data
Security
Added Security GroupComments
Better documentation for security groups
Management
Added Manager.OnInitialized hook
Handle Enum KeyValueList
Helper Methods
Added CustomActionArgs.EnsureParent/EnsureQuery
Easier parent and query access
Fixes
Fixed performance issue with keeping 1 IRepositoryUserStore in memory
Fixed issue when textsearch was replacing invalid labels
Fixed Excel issue missing last row
Maintenance
Removed Web2Assembly support
Handle ICollection as detail query
IRepositoryIdDeterminer is singleton
September 2022
New Features
Report Enhancements
Added ReportTokenGenerator
Allow per-deployment Report tokens
Report/Register expects User
Helper Methods
Added DoIf conditional execution helper
Automatic handling of SortExpression based on naming
Fixes
IDataProtectionProvider is only needed for useDataProtection
Azure storage added more places to retry before failing
Improved retry logic
Value Objects
Added ValueObjects.PreferFullRootId
Sample code for handling root property on value objects
API Security
Added ApiArgs.GenerateSignedRequest helper
Make sure we use the same logic for IsValidSignature
Fixes
Fixed issue #314
Fixed issue #323
Fixed issue #325
IExceptionService tweaks
Maintenance
Nullability improvements
January 2022
New Features
.NET 6 Features
.NET 6 typed headers support
Prefer .NET 6.0 one-shot methods where possible
Azure Storage
Added AzureStorageContainer
Better Azure storage integration
Builder Support
Allow TranslatedString for builder
Fixes
Fixed ApiArgs.IsValidSignature
Fixed issue where POA.SortExpression has other type
RavenDB enum searching fixes
Maintenance
IHostApplicationLifetime is a singleton
Show extra info when IUpdatableLog is in progress
Comments Web² vs web 3
Note: Commits marked with (test) or [skip ci] have been excluded from this changelog as they are internal testing commits.
Changelog 2023
December 2023
New Features
AsyncStreamingAction
Added AsyncStreamingAction for handling streaming responses
Added StreamingDialogOptions for customization
Added AuthenticatedRequest support on AsyncStreamingAction
.NET 8.0 Support
Added .NET 8.0 support
Updated packages to .NET 8
Builder Enhancements
Exposed more information on IBuilder interface
Better introspection capabilities
Fixes
Fixed ScimHandler not handling NameInUse correctly
Fixed PostgreSQL invalid SQL
Re-enabled TypeForwardedAttributes
Maintenance
Removed Eazfuscator obfuscation
Better handling of POA column/columnspan
Updated Web3
Added benchmarker for performance testing
November 2023
New Features
Vidyano.Abstractions Package
Added new Vidyano.Abstractions package
Moved ServiceLocator to Abstractions
Moved IUpdatableLog/LogType to Abstractions
API Enhancements
Added ApiArgs.HttpContext for better request context
Added reload when action is changed in Management
RepeatingJob Features
Added RepeatingJob.CanExecute for conditional execution
Better job control
Testing Support
Added CustomActionArgs constructors for testing purposes
Fixes
Remove starting, duplicate and end separators from Program Units
Reset ObjectId on Save if it failed
Correctly dispose CustomAction if created
Maintenance
Updated packages
Improved nullability annotations for Manager.GetUser
Fixed version for Vidyano.Abstractions
October 2023
New Features
Security Enhancements
Added IRepositoryUserRevocationStore interface
RavenDB: Use in-memory revocation store
RavenDB: Added IRepositoryUserRevocationStore support
Settings Builder
Added ISettingsBuilder.AsReadOnly for read-only settings
Export Features
Added ExportToExcelArgs.IncludedIdColumnName
Customize ID column naming in Excel exports
Tools
Added Tool FindMissingDefaultTranslations
Helps identify missing translations
Fixes
SECURITY: Fixed F-2023-0639 - Information leakage vulnerability
Resolved target context of PO based on context type of POActions (#366)
Maintenance
Keep client code in-sync for Boolean ToDisplayValue
Various performance and nullability improvements
Updated test projects to Web3
September 2023
New Features
Import/Export Enhancements
Added Import/Export of Descriptions
Added IncludeId feature for ExportToExcel
Better data portability
MetadataDescription
Added MetadataDescription for better metadata handling
ProgramUnitEx
Added ProgramUnitEx for extended program unit functionality
Fixes
Fixed issue #365
RepeatingJobHost: Handle TaskCanceledException
Fixed loading entity from index in RavenDB
Maintenance
Prefer literal contains for better performance
Help developer when reference points to value object
Improved fullTypeName handling
August 2023
New Features
ObjectId Enhancements
Added ObjectId.FromServiceString method
Easier object ID conversion
Fixes
Fixed log type modification bug in DefaultRepositoryProvider
Fixed NRE in RavenDB
Advanced.IsValidImage fix for .NET 7
Maintenance
Better default logging to exclude EF logging in Console
Added RepositoryDocumentSession for separate session management
RavenDB: Use correct session when cleaning up verbose log entries
July 2023
New Features
Manager Enhancements
Added Manager.EnsureSettingsExist
Added Manager.GetRequiredSetting methods
Show virtual settings for easy changing
Entity Framework Improvements
GetNextUserVersion support
Fix for EF7 (extra SaveChanges)
Support for intercepting Vidyano EF modelbuilder (#361)
Fixes
Fixed issue with Web2Cdn being triggered before initializing schema
Fixed SQL connection string in tests
Maintenance
CalculatedAttribute requires at least 1 dependentOn property
Tweaked parameter naming for PO.AddQuery method
Ignore EqualityContract property from records
June 2023
New Features
OpenAPI 3.1 Support
Added OpenAPI 3.1 support (#162)
Better API documentation
Program Unit Enhancements
Added new ProgramUnitItem Separator type
Added Comment to CollectionNameAttribute
Fixes
Fixed NRE (Null Reference Exception)
Fixed separator issue when OnBuildProgramUnits is used
Maintenance
Changed some RavenDBOptions properties to be only set once
Added comments for better code documentation
May 2023
New Features
Translation Service
Added MicrosoftTranslatorService.BaseAddress
Make sure new language is added in correct sorted position
Report Access Control
Added MinimumReportAccessLevel config
Better control over report access
Hooks
Added RepositoryVerboseLogStore.EntryStored hook
Added Advanced.OnImpersonate hook
Fixes
Fixed ExportToCsv functionality
Missing ExecuteMethodOperation.OpenUrl
Use correct typehint for Web3 colors
Maintenance
Also detect [KeyValueList] on nullable enum
Updated packages
April 2023
New Features
QR Code Generation
Added IQRCodeGenerator interface
Added basic BmpEncoder for QR codes for non-Windows platforms
Task Extensions
Added TaskExtensions.FireAndForget for async operations
Fixes
Fixed Web3 issue overwriting UserSettings
Maintenance
Keep required rules for new POAWR
Keep max visibility for query types
Added Icon
Don't check for POActions´2 as base class
March 2023
New Features
Extra Assembly Support
Added support for discovering types in extra assemblies (#357, #358)
Performance
Performance improvement to ClaimSet Add
Fixes
Allow UseAuthorization to be called inside UseVidyano
Allow custom suffix for split value objects
Make sure EntityType is set on POAWR.Lookup.PO
Maintenance
EFCore: Enable AsNoTracking and ignore detached lazy loading warning
Fallback exception logger to ILogger on anything but Windows
Set correct TargetContextActionsType
February 2023
New Features
Configuration Enhancements
More IVidyanoConfiguration comments
Changed EnableJobs to be enabled by default
TypeCache Service
Exposed TypeCacheService for type management
Query Features
Added DistinctValuesArgs.IncludeNullIfNullable
Better null handling in queries
Fixes
Fixed issue with VAT as label
Fixed index out of range exception
Don't fail when trying to open content for in-memory verbose log
Maintenance
Prefer file scoped namespaces throughout codebase
Use NuGet package icons
Better default handling of WhereEntity
January 2023
New Features
Query Type Support
Added QueryType for better query categorization
QueryType fixes and improvements
Advanced Features
Added Advanced.CorrectionOffset
More calls to ApplyDataSecurity when needed
Datadog Integration
Added EnableDatadog ClientOperation
Better monitoring support
Rich Custom Logs
Added UseRichCustomLogs
Enhanced logging capabilities
Fixes
Fixed issue with GroupBy not working on interfaces (RavenDB)
Fixed KeyValueList on QueryType only, and KeyValueList on read denied
Fixed reference files
Maintenance
Show attribute visibility during synchronize (query vs read+new)
Set account before starting verbose log threads
Verify against UtcNow
Note: Commits marked with (test) or [skip ci] have been excluded from this changelog as they are internal testing commits.
Changelog 2015
December 2015
New Features
public sealed class MyCRMAdvanced : Advanced
{
public MyCRMAdvanced()
{
InstantSearchDelay = TimeSpan.FromMilliseconds(200d);
}
public override TimeSpan? GetInstantSearchDelayForUser(IUser user)
{
if (user.IsMemberOf("CantUseInstantSearch"))
return null;
// Fallback to default
return base.GetInstantSearchDelayForUser(user);
}
public override void HandleInstantSearch(InstantSearchArgs args)
{
args.MaxResults = 12; // Defaults to 15 results
var user = Manager.Current.User;
if (user.IsMemberOf("Administrators"))
{
// Some built-in searches specific for application admins
args.AddPersistentObjects();
args.AddUsers();
}
using (var context = new MyCRMEntityModelContainer())
{
var search = args.Search; // The search query from the end user
// The first parameter specifies the PO type name
args.AddRange("Customer", context.Customers
.Where(it => it.FirstName.Contains(search) || it.LastName.Contains(search))
.Select(it => new
{
ID = it.CustomerID,
it.FirstName,
it.LastName
})
.Take(4)
.AsEnumerable()
.Select(it => new InstantResult(it.ID.ToServiceString(), it.FirstName + " " + it.LastName)));
// The instant result determines the ObjectId and Breadcrumb to display the result in the menu
// For single property lookups we have an easy helper method
args.AddRange("Product", context.Products, it => it.ProductID, it => it.Name, 4); // 4 max results instead of the default 5
args.AddRange("ProductCategory", context.ProductCategories, it => it.ProductCategoryID, it => it.Name, 4);
int number;
if (int.TryParse(search, out number)) // We can skip certain tables if the search input doesn't match the expected input
{
args.AddRange("SalesOrderHeader", context.SalesOrderHeaders
.Where(it => it.SalesOrderNumber.Contains(search))
.Select(it => new
{
ID = it.SalesOrderID,
it.SalesOrderNumber
})
.Take(4)
.AsEnumerable()
.Select(it => new InstantResult(it.ID.ToServiceString(), it.SalesOrderNumber, it.SalesOrderNumber.IndexOf(search, StringComparison.OrdinalIgnoreCase) - 2)));
// The SalesOrderNumber column is a computed column ("SO" + ID) so we decrement the score by 2 for better ranking results
}
}
}
}
Nullability improvements for Advanced
Improved IsEfQuery detection
Cache SmtpConfiguration KeyValueList
RavenDB: Updated client package
RavenDB: Show log expiration information
RavenDB: LookupReference handling
Enable XML documentation generation
Nullability improvements
POA nullability
Fixed missing property for translations
RavenDB: Fixed profiler issue
Don't sort value objects
Reduce need for internal access for providers
RavenDB: PersistentObjectActionsReference in package
RavenDB: Use correct PackagePath for POAReference file
RavenDB: Prefer PersistChanges over Context.SaveChanges directly
Profiler improvements and parameter serialization tweaks
Fixed issue when ExecuteAction gets a form submit without extra files
Fixed issue with AppInitialization
Fixed obfuscation issue with nullable annotations
Fixed issue with business rules with arguments not being invoked
RavenDB: Fixed OptimizeSelect issue when working with Reduce index
RavenDB: Handle ColumnReferenceEntity with empty id
Improved logging OneTimeJobHost/RepeatingJobHost
Web2Cdn: Tweaks for cdn2
Web2Cdn: Don't append / to appsettings.json Web2Version
RavenDB: Updated RavenDB.Client package
RavenDB: Minimize database calls when user doesn't have UserSettings
RavenDB: Handle IEnumerable property text search
Return SystemLanguage for DefaultLanguage if cache is not loaded
Use Request.LogonUserIdentity instead of WindowsIdentity.GetCurrent
Fixes
Fixed issue with ReadAsExcelSheet failing with empty cells
Fixed typo in initialize sql
Model SQL requires GO instead of go
Fixed synchronize issue with inherited types on EF6
Fixed issue with dialog PersistentObject and POAWR with CanAdd
Maintenance
Handle OnPreviewLoad in Manager.GetPersistentObject
Web: Improved handling of WindowsAuthentication
Add default ReadEdit/Vidyano.Import right for all users to allow RegisterImport
Don't open PO result from ExecuteAction if HasError
Handle HasError as FaultException on Load/BulkEdit
Require explicit implementation of OnBulkConstruct to enable Bulk Edit
NuGet: Updated Newtonsoft.Json to 6.0.8
Web: Correctly handle OpenOperation of ExecuteMethodOperation "navigate" when saving IsNew PO
Web: Fixed issue with ServiceGateway.toServiceString
Change Api handler to be async
Fixed issue when creating new project
Fixed merge issue
NuGet: Updated nuspec file for Newtonsoft.Json
Updated embedded CommonMark package
Consistent behavior when calling GetQuery WebAPI with non-guid id
Fixed issue with text search replacing text inside quoted parts
January 2015
New Features
Service Actions
Added ServiceAction.Confirmation
Small tweak to keep confirmation message IsClient
Manager Settings
Added Manager.SetSetting
Added hook to determine user groups from code
Added option to specify extra options for Import
Fixes
Fixed locking issue with AppDomain.OnAssemblyResolve
Fixed issue with filtering on DateTimeOffset
Fixed issue with LogRetention not correctly handling 0
Breaking change: Query menu items for which the user only has rights for 1 or more columns will now also show
Fixed small bulkedit issue
Fixed issue with Manager.GetPersistentObject being called outside Vidyano
Maintenance
Expose Manager.TimeZone
Removed obsolete/outdated WPF related code
Ensure Vidyano is initialized/updated when using Api calls
Updated CommonMark.NET (0.6.0)
Updated EntityFramework (6.1.2)
Updated Newtonsoft.Json (6.0.7)
Use Task.Run instead of Task.Factory.StartNew
Use ThreadPool.QueueUserWorkItem instead of Task.Factory.StartNew
Updated Optimizer to allow Related.Related.Related.Property
Also allow Task as return type for Api method
Tweaked AsDetail attribute, correctly handle OnRefresh on client side
Combine OnSave with saves for details (in transaction)
Web: Fixed issue with SelectReference not triggering OnRefresh on AsDetail
Allow String to Enum as DataType (fixes EF6 issue)
Web: Fixed issue with browseReference onCompleted not being called
Web: Changed place where ExecuteMethod clientOperations are being checked to Vidyano.clientOperations
Added handling of Required/NotEmpty rule on AsDetail attribute
Fixed bug with BinaryFile inputs not being cleaned up
Web: Use delay for Open clientOperation
Web: Added ability to specify delay for "showMessageBox"
Note: 2015 was a transformative year with 257 commits introducing the JSON-based repository system, moving away from database-only storage, adding Advanced hooks, implementing Google Places, adding support for VS2015, and major improvements to the Web2 client.
5.40.2+2a48896
Thursday, November 8th, 2018
Features
Added Advanced.IsSettingValueValid method to allow checking of value for custom settings
Added PersistentObjectAttribute.SetValueWithRefresh method that will also call the OnRefresh code if needed
Added (Async)CustomAction.IsAllowed method
Added Manager.HasRepositoryConnection helper method to see if the repository database is available
Added PersistentObject.LoadingStrategy to determine how the entity should be loaded from the database
Added IQueryable.FilterByObjectId method to apply the correct Where filtering including data security
Added PersistentObjectAttribute.OptionalColumn to indicate that the column should not be shown by default
Added extra hooks for SAML 2.0 processing (DetermineSaml20Information and GenerateSaml20RedirectUrl)
Added viAudit feature that is avaiable for Administrators when verbose logging is enabled
Added Advanced.IsTrustedProxyIpAddress to allow X-Forwarded-For header for trusted proxy/load balancer/forwarded
Added WebsiteArgs.Redirect method to redirect the page load to another location (e.g. SSO portal)
Changes
Swallow “Cannot access a disposed object” exception for System.Web.WebSockets.AspNetWebSocket
Persist changed attributes after unchanged to entity
Also profile CreateUserSession
Fixes
Fixed issue on Diagnostics page when GenerateMessage would throw an exception (e.g. validation error)
Fixed issue with NullReferenceException when calling Manager.WebsiteRoot, will return null now instead
Fixed issue with new RepeatingJob not triggering
5.34.3+d278982
Monday, March 12th, 2018
Features
Added Manager.LogEntry to get client version, user agent and requestId
5.30.0+530afaf
Sunday, December 28th, 2017
Features
Added Advanced.StorageProvider to handle reading/writing of verbose log content ()
Replace authToken in verbose logs with just the expiration info
Use Setting.DataType as configured in repository (i.e. for Password the content will be hidden)
Allow custom queries from base PersistentObjectActions class
Fixed issue in ReplaceSensitiveUrlPart when Url is empty
Fixed issue where data from removed columns in QueryExecuted were still being sent to the client
Fixed issue when saving a new DataType when the project doesn’t have templates in the model.json
Fixed issue where unique index violation would also list included columns from index
Added CustomApiController.OnPreApi hook and ApiArgs.CustomMethod property
Added Advanced.HandlePasswordOrTwoFactorChanged
Added support for Swagger definitions in arguments/responses
Support UserName/AuthToken in Authorization header for Vidyano default web calls
Added support for $select on reports to only return a limited set of columns
Added parameter user on Manager.Log to log for that specified user instead of current user
Changes
Validate actual password change for ResetPasswordNextLogin
Sort swagger tags/path alphabetically
Also handle signin/signout as reserved words
Increased pwnedpasswords api timeout to 10sec
Log AzureStorageConnector auto-resume logs as Warning
Log failed sign in attempt for existing users using user in log instead of username in message
Minimize timing attack against unknown users
Fixes
Fixed issue when saving existing filter
Fixed issue when custom Api method resumes null instead of HttpResponseMessage
Fixed issue with nested repeated sections in Word.Generate
Fixed issue with exception handling in AzureStorageConnector
Added extra logging in Verbose logs (User agent, Client version, Request id and 5 custom variables) (example)
Added basic support for being a SCIM 2 service provider (example)
Added authentication support for Azure AD Single Sign-On using SAML (example)
Added sync option for hidden attributes and detail queries
Changes
Updated EntityFramework NuGet dependency to 6.2.0
Changed newline endings back to CRLF for PersistentObjectActionsReference.cs
Fixes
Fixed issue with AuthorizationSignature for reports not being checked correctly
Fixed issue with missing groups for users when enabling NoDatabase
Fixed issue when enabling or disabling verbose model
On the Security page you can configure the PO that should be shown and the application group for the user rights. For most applications the Register PO will be a new virtual Persistent Object with at least an email address (username) and password attribute. The following code shows an example POActions class for the Register PO.
public class RegisterActions : PersistentObjectActionsReference<AdventureWorksEntityContainer, object>
{
public override void OnSave(PersistentObject obj)
{
if (!CheckRules(obj))
return;
var userName = (string)obj["Email"];
if (Manager.Current.GetUser(userName) != null)
throw new FaultException("That user already exists. Use the forgot password functionality to reset your password.");
Manager.Current.CreateNewUser(userName, (string)obj["Password"], profile: new Dictionary<string, string> { { "Registered", "self" } });
obj.AddNotification("You can now login using your email and password.", NotificationType.OK);
}
}
Forgot password
When working with email addresses as user names we can use this information to provide a forgot password functionality. By implementing the HandleForgotPassword method on the Advanced class you'll get the "Forgot password?" button on the Sign in screen.
Best practice recommends for generating a random reset password token (ObjectEx.GetSecureRandomPassword can be used), storing the token in the user profile, emailing the user a link that triggers an api method that will verify the token and user combination. At that moment you can use the IUser.ResetPasswordNextLogin() method to trigger a password change on next login and redirecting the user to an existing logged in session.
// In [Schema]Advanced.cs
public override void HandleForgotPassword(ForgotPasswordArgs args)
{
// NOTE: Always inform for success so that we don't leak information about users
args.Notification = "An email has been sent with all the information to reset your password.";
var user = Manager.Current.GetUser(args.UserName);
if (user == null)
return;
var userHostAddress = Manager.Current.RequestMessage.GetClientIpAddress();
var token = user.Profile["ResetPasswordToken"];
if (string.IsNullOrEmpty(token))
{
token = ObjectEx.GetSecureRandomString(16).Replace("-", null).Replace("_", null);
user.Profile.SetValue("ResetPasswordToken", token);
}
var location = Manager.Current.WebsiteRoot + $"api/ResetPassword?UserName={user.Name}&Token={token}";
// TODO: Send email to user with information (password change requested, from ip, location to click, ...)
}
// In [Schema]Web.cs
public IResult ResetPassword(ApiArgs args)
{
var userName = args.Query["UserName"];
var token = args.Query["Token"];
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(token))
return Results.Problem("Invalid request", statusCode: 400);
var user = Manager.Current.GetUser(userName);
if (user != null && token == user.Profile["ResetPasswordToken"])
{
user.Profile.SetValue("ResetPasswordToken", null); // NOTE: Resetting the token can be a problem if the user doesn't complete the change password prompt
user.ResetPasswordNextLogin();
var encodedUser = Convert.ToBase64String(Encoding.UTF8.GetBytes(user.Name)).Replace('/', '_');
var authToken = WebController.GenerateAuthToken(user.Name, DateTimeOffset.Now.AddDays(28), Manager.Current.RequestMessage.GetClientIpAddress()).Replace('/', '_');
var redirectUrl = Manager.Current.WebsiteRoot + "#!/SignInWithToken/" + encodedUser + "/" + authToken;
return Results.Redirect(redirectUrl);
}
return Results.Problem("Invalid request", statusCode: 403);
}
5.25.3+8224b3b
Tuesday, September 19th, 2017
Features
Added extra per PO unique salt for securing the SecurityToken
Added support for using anonymous types in custom queries
Added default MinLength business rule
Added support for per query user rights to give user/group access to a single query instead of all queries of a persistent object
Added Manager.UpdatableLog method to get a Vidyano log entry that can be changed
Added Advanced.PreNewFeedback hook for adding extra attributes on New Feedback
Added PO/Query property to override label for specific action
Added Advanced.OnLogin hook to show extra PO to end-user before the application can be used
Added Report.Description for optional description
Added a Profile detail query on User to see the current profile values
Added caching of all Web2 CDN resources when a version is requested (can be disabled using the Vidyano.DisableWeb2CdnPreload appSetting)
Changes
Made ObjectEx.GetSecureRandomString public
Made some changes to action based user right (new NewDelete combined right, grouped rights, …)
Made Report.Token optional, a report without token is disabled
Fixes
Fixed issue with non-sliding auth token not working on ADFS via ACS
Fixed incompatibility issue with .NET standard System.Net.Http package when receiving large request
Better detection for mapped code first entities
Best Practices
Configuration Settings
If your deployment allows for configuring settings outside of the source code (e.g. the Application Settings tab on Microsoft Azure App Services) then this can be used to configure a set of application settings that even the developers won't have access to.
Security Tokens
Critical: Replace all security tokens in production environments. The default tokens generated during development should never be used in production as they may be committed to source control.
Replace the following tokens in your production configuration:
ApplicationSalt (via the Vidyano:ApplicationSalt app setting)
DiagnosticsToken (via the Vidyano:Diagnostics app setting)
ObjectIdsSalt (via the Vidyano:ObjectIdsSalt app setting)
PowerShell Token Generator:
Use this PowerShell snippet to generate secure random tokens matching Vidyano's token generation logic:
This outputs JSON-formatted values ready to copy-paste into your configuration.
Cookie-Based Authentication
Recommended: Enable cookie-based authentication for enhanced security in web applications.
By default, Vidyano stores authentication tokens in browser storage. For improved security, you can enable secure, HttpOnly cookies via the CookieBasedAuthentication setting:
Benefits:
Authentication tokens stored in secure, HttpOnly cookies (not accessible via JavaScript)
Better protection against XSS attacks
Automatic cookie transmission with requests
Compatibility notes:
Safe to enable for standard web applications
If your application calls Vidyano APIs directly (e.g., from external services), ensure your HTTP client library has cookie store support enabled
The Vidyano.Core NuGet package has this enabled by default since v5.53.0
Other Configuration Settings
Use a different set of credentials/connection string for the database
If configured, use another connection string for verbose logging
Enable the Vidyano:ForceHttps app setting to enable HSTS
Code Configuration
Rate Limiting
Enable rate limiting to protect against abuse and brute-force attacks. Rate limiting is disabled by default and can be enabled in your appsettings.json:
This enables the default Moderate level with rate limit headers included. You can customize the level if needed:
Available levels:
Level
Read/min
Write/min
Use Case
The rate limiting feature includes:
User-based partitioning - Works in intranet environments without IP-based issues
Read/Write classification - Different limits for read vs write operations
Distributed Cache (Optional)
Recent versions of Vidyano include automatic in-memory rate limiting and 2FA token validation. However, you may still want to add a distributed cache in these scenarios:
Multi-instance deployments - When your application runs across multiple instances, pods, or servers
Persistence across restarts - To maintain rate limit counters and 2FA validation state when the application restarts
Redis Cache (Recommended for production):
Install the NuGet package, then configure:
SQL Server Cache:
When IDistributedCache is registered, Vidyano will automatically use it for rate limiting and 2FA validation. Otherwise, it falls back to in-memory caching (per instance).
Security Headers
Add security headers to protect against common web vulnerabilities. The GetWebsiteContent method in your [Schema]Web class is called for the initial HTML page and is the ideal place to add security headers:
Important: Review and adjust the Content-Security-Policy based on your application's specific needs. The example above is a starting point that may need to be relaxed for certain features.
Automation protection
If the web app is available on the public internet and can be accessed without logging in (e.g. contact form) you should provide extra protection against abuse. This can easily be done by using the Google reCaptcha library to validate the request.
External Audit
Vidyano has been externally audited by The Security Factory, you can read the report , , .
“Overall Security Posture
Based on our experience we would rate the security posture of the application in the higher regions of good security.”
Changelog 2017
December 2017
New Features
SCIM 2.0 & Azure AD SAML SSO
Implemented SCIM 2.0 Service Provider
Added Azure AD SAML SSO support
Enterprise identity management integration
Reports Security
Added Report Access/Compromised tracking
Report security improvements
PowerShell examples for reports
Fixes
Fixed issue #139
Fixed builder issue when vidyano project is inside solution folder
NoDatabase issue with security.json file with groups
Maintenance
Added sync option for hidden attributes and detail queries
Changed default project web.config
Extended verbose logging
November 2017
New Features
Advanced Hooks
Added Advanced ACS hook to passthrough a custom domain
Added hook to customize index.html for websites
Changed BlacklistedPasswords to IsPasswordBlacklisted
User Management
Allow User/NullableUser data type for String property
Fixes
Fixed issue #131
Fixed issue #103
Fixed issue with changes to custom settings not showing until restart
Maintenance
Made POA.GroupName setter public
Added DEV indication for exception
Added application start time
October 2017
New Features
User Management
Added IUser.IsEnabled/Enable()/Disable()
User enablement/disablement functionality
Query Actions
Added QueryAction enum with built-in query actions
Better query action organization
Fixes
Fixed issue #121
Fixed issue #122
Fixed issue #125 - Manager.DeleteUser
Fixed issue with ExecuteAction through form using 100% CPU in chrome
Maintenance
Allow API/Instant request using default user
Excel changes
Added property order overrides for json serialization
September 2017
New Features
Per-Query User Rights
Added support for per query user rights
Introduced Query.HasRight
Extended UserRightActions to support per query user rights
IUpdatableLog (#105)
Added IUpdatableLog interface
Better log management
Action Labels (#109)
Added PO/Query ActionLabels
Better action organization
Anonymous Queries
Added support for anonymous queries
Made Report.Token optional
Fixes
Fixed issue #99 - salted PO
Fixed issue #101 and #102
Fixed issue with signing in using ACS for non-sliding auth token (#97)
Maintenance
Made email part of feedback async
Made request reading async/await
Added feedback hooks
Don't send Initial PO for default user
August 2017
New Features
Security Enhancements
Security architecture documentation
Security audit overview
Changed security screen to be more compact
Preview Loading
Added PreviewLoadArgs.HandleAsNew method
Better control over preview loading
Fixes
Fixed issue #87
Fixed issue #89
Fixed issue #91
Fixed issue with DefaultPersistentObjectActions being used for Vidyano
Maintenance
Handle NRE for #83 when no responses are defined
Detect ComplexType as mapped classes
Missing updated seeder hash
July 2017
New Features
Password Security
Updated password recommendations
Better password handling
Query Options
Added option to skip computing of total items
Better query performance
Developer Actions
Added viDuplicate dev action
Fixes
Fixed issue #33
Fixed issue #70
Fixed issue #72
Fixed issue #76
Maintenance
Consistent handling of TargetInvocationException
Log unhandled api errors
Added remark for Advanced.HandleForgotPassword
June 2017
New Features
Forgot Password & Registration
Added ability to define Register PO and handle Forgot password
Better user onboarding
Detail Rules
Added CheckDetailRules for improved check rules on Detail attribute
Fixes
Fixed issue #53
Fixed issue #66
Fixed issue #67
Fixed issue when adding language and no microsofttranslatorappid exists
Maintenance
Changed .Legacy target framework to 4.5
C# 7 refactor throughout
Don't initialize PO ActionCodes/HelpSet to empty collection
Fixed issue with IUser.Profile[] returning Settings data
Fixed issue when AutoQuery is enabled during OnConstruct(query, parent)
Fixed issue with Null JToken on ToServiceString
Maintenance
Don't block application start when cleanup of CacheUpdates/Logs fails
Respect developer CanSort options for existing user sort options
C# 7 refactor
April 2017
New Features
Azure Storage
Added AzureStorageAccount helper class
Use Azure storage REST API
Improved AzureStorageConnector
Developer Actions
Added viRestartWebApp action
Added viRegenerateToken action
Date Filters
Added LastXDays filter for dates
Better date filtering
Fixes
Fixed issue #1
Fixed issue #24
Fixed issue #55
Fixed issue #56
Maintenance
C# 7 refactor throughout
Improved performance when searching verbose logs on Created on
Removed obsolete Instant PO
March 2017
New Features
Instant Search (#46)
Added instant search functionality
Added input validation for instant search methods
Web2 CDN
Introduced local cache for Web2 CDN requests
Client version change notifications
Per website web2 version support
API Features
Added ApiMethod.NeedsAuthentication
Allow Vidyano Setting overrides using AppSettings
Fixes
Fixed issue with empty column for csv reports
Fixed issue with empty language value not being set if same as English
Fixed issue with some translations being incorrectly reused
Maintenance
Added Advanced.Poll hook
Only check Web2Version setting if ManagerImplementation is Initialized
Removed tag for new web components
February 2017
New Features
Export to CSV (#27)
Added CSV export functionality
Better data export options
Advanced Features
Added Advanced.PostFeedback
Better feedback handling
Fixes
Fixed issue #28
Fixed issue when using Manager.GetPersistentObject not passing correct ObjectId when changed
Fixed issue with exception in custom Web class constructor not being logged correctly
Maintenance
Made IOffset public
Added release notes
Tweaked default .tsconfig
Fixed builder issues with new semantic versioning
January 2017
New Features
User Management
Added Manager.GetUsersForGroup
Better group management
PersistentObject Methods
Added PO.RemoveAttribute/AddQuery/RemoveQuery
More flexible PO manipulation
ServiceAction
Added ServiceAction.KeepSelectionOnRefresh
Better UI state management
Fixes
Fixed issue #23
Fixed issue when bulkediting POs
Fixed issue with bulkediting UserRights
Fixed issue with CreateTransactionScopeForAction not working with profiler
Maintenance
Changed TargetFramework to 4.5.2 (then back to 4.5)
Use NuGet for DocumentFormat.OpenXml (#19)
Missing translations
Note: 2017 was a massive year with 400 commits focusing on C# 7 refactoring, security enhancements, SCIM 2.0 implementation, instant search, Web2 CDN improvements, and numerous performance optimizations.
Changelog 2016
December 2016
New Features
OAuth Provider
Exposed OAuthProvider (#15)
Better OAuth integration
Fixes
Fixed bulk-edit not working on User (#12)
Fixed NRE when saving existing group
Fixed issue with Excel rows using 1-based index
Security
Increased entropy for new report token
Don't send HSTS header when running on localhost
Maintenance
Translations improvements (#17)
Made route suffixes opt-in
Don't log ThreadAbortException/TaskCanceledException in ExecuteAsync
November 2016
New Features
Transactional Logic
Added transactional logic (opt-in)
Added POActions.OnBulkSave
BREAKING: Removed default code from OnRefresh
Builder Updates
Updated solution to VS2017 RC (15.0)
Use Web² by default
Changed default Web template to include recommended options in web.config
Fixes
Fixed issue with PU Items not being sorted when added using AddQueriesToProgramUnit action
Fixed issue when creating new project
Maintenance
Also send referrer to CDN for web2 requests
Extra information when logging
Fixed issue with UpdateVidyanoVersion.exe
October 2016
New Features
Verbose Model JSON
Added ability to save/load verbose model.json
FileSystemWatcher for model changes
Session support for verbose model
User Management
Added ability to rename user from code
Fixed cache invalidation
User rename tweaks
Fixes
Fixed issue when synchronize needed to add new settings
Fixed NRE when display attribute of POAWR does not exist as property
Fixed issue with detail attributes being created together with their parent
Maintenance
Advanced: Added ability to change or disable IP used for auth token
Always prefer using the request uri with correct schema (X-Forwarded-Proto)
Keep current DisplayAttribute on POAWR when changing lookup and it exists
September 2016
New Features
Swagger API Definition
Added option to define swagger api definition
Added SwaggerContactAttribute
Allow defining of response type
Dialog Actions
Added new Action.ShowedOn option Dialog
Show custom action in a Persistent Object Dialog
API Extensions
Extended API to support commonly used cases (versioning, authorization, paths)
Fixes
Fixed issue with two factor login
Fixed issue with IsWord rule showing wrong message
Fixed issue when renaming PO
Maintenance
Build Vidyano.Core as NuGet package
Allow native navigation for websites
Fix common model.json merge issues
August 2016
New Features
Two-Factor Authentication (2FA)
Implement basic 2FA checker
Store two-factor token in user table
QR code generation for 2FA
Show code label on sign-in page
Fixes
Fixed issue with new dates that aren't visible
Fixed issue when filtering on null
Fixed unknown NRE issue
Maintenance
NoDatabase: Correct store user profile
Don't block repository schema upgrade when development is disabled
Tweaked ExecuteQuery, get count/totalItems first, if zero skip rest
July 2016
New Features
Wizard State
Added AsWizard state behavior
Wizard PO support
Default Values
Added POA.DefaultValue
Allow custom default value
Added DefaultValue/CustomDefaultValue to POABuilder
Web2 CDN Handler
Added simple Web2 handler that uses CDN
Allow override for Web2 version on CDN
Fixes
Fixed issue when you change a POAWR that has a linked POAWR
Fixed issue with GetReport to xml and 0x00
Fixed Azure issue when proxying CDN
Maintenance
Added OnHelp hook
Removed hardcoded dependency for WindowsAuthentication on HttpContext
Fallback to WindowsIdentity.GetCurrent() instead of null for GetClientIdentity
June 2016
New Features
Custom API Controller
Extract base CustomApiController class from CustomWebController
Better API abstraction
Notification Duration
Added NotificationDuration
Control notification display time
Auth Token Validation
Added WebController.ValidateAuthToken
Exposed HttpEx
Fixes
Fixed issue with delete and check violation throwing ValidationException
Fixed issue when deleting query
Fixed issue with adding custom filters
Maintenance
NoLicense: Don't use License settings anymore
Websites: Classic -> Legacy and Web2 -> Default
Added option to include custom filters from code
May 2016
New Features
Retry Action
Added ability to ask end-user for confirmation/more information during ExecuteAction
Handle retry logic on actions
Added ability to include PO with RetryAction
Fixes
Fixed issue with MinValue/MaxValue business rule on nullable properties
Fixed issue with multiple CORS handlers
Fixed pages issue in Websites
Maintenance
Added ability to specify if SelectAll is enabled for a Query
Tweaked outdated browser behavior
Include correct HTTP code when requesting report that has an error
April 2016
New Features
Builder Enhancements
Allow removing of attributes on PO
Added DataTypes.Determine method to detect the best DataType
Allow setting of ReferenceBreadcrumb in builder
Advanced Hooks
Added ability to persist user settings during SaveUserSettings
Added GetKey hook
Added hook for unknown custom action method
Fixes
Fixed issue with routes not being updated when PU/PO/Q is changed/added
Fixed issue with CanRead being false in QueryExecuted when ExecuteQuery is used
Fixed issue with NoDatabase and using Builder
Maintenance
When creating new group/tab from builder also set Name
Added ability to specify different breadcrumb when displaying on reference (POAWR/QRI)
Fixed issues when bulk-editing POAs
March 2016
New Features
Visual Studio Integration
Added VisualStudioIntegration
Builder: Support extra buttons from Vidyano.Service
Builder: Don't lock referenced Vidyano.Service
Websites Features
Allow groups for reports as well
Advanced: Allow custom profiler entries
Fixes
Fixed issue when creating new DataType
Fixed issue with title being set on vi-app instead of label
Fixed issue with invalid query sortoptions for reports
Maintenance
Expose X-ElapsedMilliseconds when using CORS/Profiler
Websites: Also check virtual path ignoring case
Prefer namespaces for webcomponent's ts
February 2016
New Features
Websites and Pages
Initial commit for Websites/Pages
Watch websites files for changes and update cache
Allow reordering of pages
NoDatabase Mode
Load settings from settings.json (with first-time migration)
Load users from users.json (with first-time migration)
Handle Saving/Deleting of users/groups
Fixes
Fixed issue with old UI and OnAddReference
Fixed issue when saving website changes
Fixed issue when website binding ends with /
Maintenance
Expose Website on Manager.Current
Added option to specify Id for GroupBuilder
Keep highest NotificationType when adding a notification
January 2016
New Features
NoDatabase Support
Initial NoDatabase implementation
Settings, users, and groups stored in JSON files
First-time migration from database
DbGeometry Support
Added support for DbGeometry
Spatial data handling
Fixes
Fixed a bug with formatted negative numbers
Fixed issue with LogsVerbose failing when repository database is not available
Fixed issue with verbose logging when the TargetContextType contained invalid characters
Maintenance
Give priority to QueryResultItemValue typehints over QueryResultItem
Change viConfigure actions to use Navigate ClientOperation
Show more information when EfObjectConverter.cctor can't load assembly types
Note: 2016 was a transformative year with 330 commits introducing NoDatabase mode, Websites/Pages functionality, Two-Factor Authentication, Swagger API support, Visual Studio integration, and the transition to Web2 as default.
Grouping
These screenshots are from older versions, some minor UI changes can be expected
An opt-in feature that should be enabled per attribute that an user can group on. Will allow them to see the query grouped by the attribute that they selected instantly showing the count per group and the ability to collapse those groups.
You can use this feature by setting the “Can group by” to Yes on the attribute.
Users can then use the context menu on a query grid to enable grouping for that attribute.
dotnet new install Vidyano.Templates::1.0.20241119.5814
Trust the development certificate (needs to be done once on a development machine)
dotnet dev-certs https --trust
You only need to do this once.
Create your first Vidyano application
The latest version currently is 6.0.20250305.5880 (you can check the .csproj file for the version you are referencing), in most cases you can immediately update your even before running the application.
Documentation
Persistent Objects
Persistent Objects in Vidyano are utilized to represent various data structures, including:
Tables: Directly mapping to database tables.
Collections: Representing groups of related items.
Entities: Defining individual records or objects.
Virtual Forms: Describing forms with a set of fields without a direct database mapping.
Key Features
Flexibility: Capable of representing both physical and virtual data structures.
Customization: Allows for the definition of fields, relationships, and behaviors tailored to specific needs.
Use Cases
Data Representation: Managing complex data structures within the application.
Form Design: Creating virtual forms to capture and process user input efficiently.
Persistent Objects are a fundamental component of Vidyano, providing a versatile mechanism for data management and interaction.
Queries
Queries in Vidyano are used to retrieve and display data in various ways. There are three primary types of queries:
Context Property Queries
These queries map directly to a property on the context, typically representing entire database tables. They are straightforward and provide a direct view of the underlying data.
Detail Queries
Detail queries are used to fetch data related to a specific entity. They display records based on their parent entity, allowing for a focused view of related data.
Custom Queries
Custom queries offer the most flexibility, allowing developers to implement complex business logic in code. These queries can filter data, retrieve information from external services, or provide customized views tailored to specific needs.
Each type of query serves distinct purposes and provides a powerful mechanism for data retrieval in Vidyano.
Examples
Persistent Object Attributes
Attributes in Vidyano represent individual fields within a Persistent Object. They can be:
Linked Attributes: Directly connected to a class property.
Virtual Attributes: Used in code but not mapped to a database field, ideal for scenarios like contact forms or additional processing options.
Attributes contain detailed metadata such as:
Name: The identifier for the attribute.
Data Type: Specifies the type of data (refer to the Data Types section for more details).
Position: Determines its placement in the interface.
Attributes also have customizable hints, such as displaying a dropdown as a select box or radio buttons. This flexibility allows developers to create intuitive and user-friendly interfaces.
Data Types
Vidyano supports a range of built-in data types to represent different kinds of information:
Primitive Types: Includes basic types like string, integer, datetime, and datetimeoffset.
Multiline String: Provides a text area for users to input large amounts of text.
Developers can also create custom data types to represent specific business needs:
Custom Data Types: For example, an IBAN bank account number or a phone number. These can be reused across the application and have specific logic for display and input.
Data types dictate how information is presented, whether in a persistent object or within a query. For instance, an Image Data Type might display the image directly in a query, while in edit mode, it allows users to upload or paste a new image.
This flexibility enables developers to tailor the application to specific requirements.
Business Rules
Business Rules in Vidyano allow you to enforce predefined validation rules across your application. Some of the built-in rules include:
NotEmpty: Ensures that a field is not left empty.
Required: Mandates that a field must be filled.
Min/MaxValue: Sets minimum and maximum values for numeric fields.
In addition to these, developers can write custom business rules in C# to handle more complex validation logic. This involves:
Custom Validation: Writing code to evaluate the data input by the user and determine if it meets the required criteria.
Error Messaging: Displaying validation error messages when the input does not comply with the rules.
Business Rules provide a robust mechanism for maintaining data integrity and ensuring consistent validation throughout the application.
PersistentObjectActions
The Actions class in Vidyano is linked to specific Persistent Objects and is crucial for implementing custom logic, named following the [PersistentObject]Actions convention. Key functionalities include:
Custom Logic: Execute code when an entity is loaded, created, saved, or deleted.
Query Execution: Add logic when executing queries, enhancing data processing.
Versatile Methods: Provides various methods to handle different stages of an entity's lifecycle.
This class is widely used for customizing application behavior, providing developers with powerful tools to manage
The Legacy v5.x also contains relevant information about .
Custom Actions
Custom Actions in Vidyano are user-defined actions, typically represented as buttons, that can be placed on Persistent Objects or Queries. They provide a flexible way to extend functionality.
Key Features
Role-Based Visibility: Custom Actions can be controlled via user roles, allowing developers to specify when and where these actions are visible.
Contextual Behavior: On a Query, actions can be configured to require conditions, such as
Examples of Using Custom Actions
Custom Actions can be used for a variety of tasks within Vidyano. Here are a few practical examples:
Send Email Action: This action can be used to send an email to a selected customer. When triggered, it opens a predefined email template and sends it to the customer's email address.
Import Data Action: This action can be placed on a customer query, allowing users to import data from a file. When the import button is clicked, a dialog appears for selecting a file, and the data is imported accordingly.
Download Action: This action allows users to export download data for a specific Employee. When the user clicks the Download button, the data is fetched and will show a download dialog in the browser to save the result.
These examples illustrate the versatility of Custom Actions, enabling developers to extend Vidyano's capabilities to meet specific business needs.
Menu
The menu in Vidyano provides a structured way for end users to navigate through the application. It consists of:
Program Units: Higher-level items in the menu that can be easily shown or hidden based on user rights. Each application can have multiple program units.
Program Unit Items: These are links within a program unit and can point to a query, a persistent object (e.g., an account page), or even an external URL.
The entire menu system is driven by user rights, ensuring users only see the options they have access to. Additionally, developers can implement hooks to further control the visibility of program units or dynamically add new values.
This system offers a flexible way to organize and manage the application's navigation, enhancing user experience.
Web API Hooks
Vidyano allows you to extend your application by adding custom API methods. Each application comes with a predefined web file, named using a specific naming convention ([schema]Web), which acts as a built-in API controller.
Key Features
Custom Methods: You can add methods that are accessible via the /api/[methodName] endpoint.
Flexible Authentication: API methods can be configured to require authentication, support anonymous access, or use custom authentication mechanisms.
ApiArgs: Each method receives an ApiArgs
This system offers a flexible way to extend your application's functionality, allowing you to handle various scenarios and integrate external services seamlessly.
Settings
Vidyano provides a variety of settings that can be configured to tailor the application to specific needs. These include:
Built-in Settings: Accessible from the management interface, these settings cover a range of configurations, such as:
SMTP Configuration: For managing feedback or email sending settings.
Default Language and Culture: Setting the application's default language or cultural preferences.
These settings provide a flexible mechanism to customize the application behavior, from basic configurations to more complex feature toggles and external service settings.
The Legacy v5.x documentation also contains relevant information about .
Logging
Vidyano includes a built-in logging system that records events and errors, storing them in the database (SQL or RavenDB). Key features include:
Automatic Logging: The application logs important events automatically, such as metadata synchronization, incorrect sign in attempts or faults.
Error Logging: Records exceptions and faults, providing developers with detailed information during development and troubleshooting.
Custom Logging: Developers can add custom logs via code, useful for tracking specific events or processes.
This robust system ensures that developers have comprehensive insights into application behavior and can quickly identify and resolve issues.
Verbose Logging
Vidyano also supports a concept, where all requests are logged automatically with detailed information. This feature is invaluable for advanced troubleshooting and collecting metrics, allowing developers to gain deeper insights into application performance and user interactions.
Advanced Topics
Authenticator Service
The Authenticator Service in Vidyano is based on a naming convention ([schema]AuthenticatorService) and extends the base Authenticator Service class. This class is crucial for mapping users and verifying credentials. Key functionalities include:
Default Authentication: Uses BCrypt-encrypted passwords stored in the database.
External Providers: Supports integration with external authentication providers like Azure AD, Google, and Microsoft.
Custom Authentication: Allows implementation of custom password logic.
The Authenticator Service provides extensive flexibility, enabling developers to tailor authentication processes to specific requirements.
Check the legacy v5.x documentation about configuring
Advanced Base Class
Vidyano includes an advanced class, named using a specific naming convention ([schema]Advanced), that provides numerous hooks to extend or modify built-in features. While these hooks are less frequently used, they are invaluable for specific scenarios.
The Advanced class is ideal for developers needing fine-grained control over the application's behavior.
Courier Messaging
See related document , can be used in RavenDB for message based communication.
Context
The Context class in Vidyano is a core component used for database interactions. Named following the [schema]Context convention, each application has at least one Context class. Key features include:
Database Interaction: For SQL Server, it's based on Entity Framework's DbContext. For RavenDB, it wraps the IDocumentSession.
Scoped Service: A single instance per request, used across the application.
Data Management: Provides properties for tables or collections and includes helper methods to add, remove, and save changes.
The Context class is essential for managing data access and interactions, providing a flexible and powerful way to handle database communication.
Custom UI
Vidyano offers a default user interface out-of-the-box, allowing you to run applications without writing HTML or JavaScript. However, you can create custom components for specific needs, such as new data types or unique UI elements.
Custom UI is particularly useful for:
New Data Types: When adding new data types, you can design custom UI components.
Unique Requirements: For cases where the built-in UI doesn't meet your needs, custom components allow full control over the interface.
This flexibility ensures you can tailor the user experience to your application's unique needs.
Source code is available on https://github.com/Vidyano/vidyano together with a sample Vidyano application to showcase the different data types.
Samples
This section provides a collection of sample projects and code snippets to help you understand various use cases. These samples are designed to be downloaded and run, offering practical examples of how to implement different features in Vidyano.
While the full details are found in the code, the documentation highlights:
Common Use Cases: Real-world scenarios demonstrating key Vidyano features.
Code Examples: Sample code illustrating how to achieve specific tasks.
Downloadable Projects: Ready-to-run projects you can explore and adapt.
These samples serve as a practical reference, helping you to quickly grasp how to leverage Vidyano's capabilities in your own projects.
Sample Projects
Web3: Web3 is a sample Vidyano application that showcases various data types and custom UI components. It provides a comprehensive overview of Vidyano's capabilities and how to implement them in your projects.
VidyanoRavenSample: A sample project demonstrating how to use RavenDB with Vidyano. It includes a basic setup and configuration to get you started with RavenDB in Vidyano.
Tips and Tricks
Vidyano offers several developer-centric features to enhance productivity:
Profiler: Open the profiler while the application runs in the browser to view details of requests, including methods called, parameters, database calls, and performance metrics.
Control + Right-Click: Use this shortcut to open a pop-up menu for quick navigation within the management interface.
Impersonation: Test various user roles by impersonating users without needing to log in separately.
These features streamline development and testing, making it easier to manage and optimize your Vidyano applications.
This document provides a structured guide to working with Vidyano. For further details, explore each section and refer to the provided code snippets.
5.28.2+bc49431
Thursday, November 30th, 2017
Features
Added Advanced ACS hook to passthrough a custom domain
Added Manager.StartTime property to get AppDomain start time (also available in diagnostics)
Added support for byte/sbyte/short/ushort/uint properties for Display on total
Added CustomApiController.GetWebsiteContent hook to customize html for a website index.html
Changes
Allow authenticated API calls and Instant Search using default user
Made PersistentObjectAttribute.GroupName setter public
Replaced Advanced.BlacklistedPasswords property with Advanced.IsPasswordBlacklisted method
Fixes
Fixed issue when throwing ValidationException using a single message
Fixed issue when using Builder to create/update messages
Fixed issue when changing custom settings not showing new value until application restart
2.0.0
Breaking Changes
Removed shim libraries and thereby out of the box support for Internet Explorer
This version drops out of the box support for Internet Explorer. This means a lot of the shim libraries have been removed in favor of adding the following code to your index.html:
Note that this will also be the last major version of the Vidyano web client that will support Internet Explorer at all.
Upgraded Typescript to version 3
This update together with the removal of the shim libraries (see below) will require you to add a lib section to the tsconfig.json file:
Deprecated LINQ for JavaScript and removed all references from base library
The most major breaking change is the deprecation of the linq.js base library.
The bad news
all code using LINQ for JavaScript will write a deprecation warning to the console. The next major version of the client will no longer include the library by default.
The good news
we added replacements for the most used functions directly on the native JavaScript Array prototype.
you can easily include the library if you choose not to migrate your code. Simply add the following line of code to the ```<head>``` element in your index.html file:
adding this code below the Vidyano import will also get rid of the deprecation warning in version 2.
Migrating away from linq.js
Enumerable.from
Can be omitted in most cases as the argument will most likely be an array already. In case the argument is for example a DOM NodeList, you can use the native Array.from() function instead:
Array extensions
Enumerable.SelectMany
SelectMany can be easily written with native JavaScript:
What's New
Tags
You can now add the inputtype=tags typehint to a MultiString attribute to display the strings as tags.
is-ie attribute on vi-app
This attribute is now added automatically to the vi-app element so the child elements can more easily add custom styles via :host-context specifically for Internet Explorer.
Changelog 2024
December 2024
New Features
Metadata Lookups (#381)
Added metadata lookup system
Better data relationships and lookups
Query Enhancements
Added ColumnOverride.IncludeAllContent
Include all content in query results
Options
Added option to disable courier and inform if no recipients
Better message handling control
User Creation
Added CreateForUser with OriginalUser
Track original user in impersonation scenarios
Fixes
TimeZone America/Nuuk was renamed
TimeZone Europe/Kyiv was renamed
KeyValueList distincts wrong when text search is used
November 2024
New Features
.NET 9.0 Migration
BREAKING: Migrated to .NET 9.0, removed .NET 6.0 support
Take advantage of latest performance improvements
InitializeByCtorAttribute
Added InitializeByCtorAttribute
Support for constructor-based initialization
Idempotent courier messages (RavenDB)
Prevent duplicate message processing
Performance Optimizations
Optimize .Run for non-enumerables
LeastRecentlyUsedCache/Set implementation
Builder optimizations
Fixes
Typo in SynchronizeBlacklist
Certificate loading on .NET 9 (RavenDB)
Keep POAWR casts logic in sync with FromServiceString
Maintenance
Updated packages
Builder marked as disposable with lazy scope creation
Use LINQ and collection expressions
October 2024
New Features
(RavenDB)
Added Courier for message queuing
Support for delayed messages
MessageType hook for custom handling
.NET 9.0 Support
Added .NET 9.0 support
Prepare for next LTS release
TranslatedString Improvements
Added TranslatedString.DefaultGetLanguages
Various TranslatedString improvements
Better multilingual support
CLI Enhancements
Added vidyano-synchronize-schema CLI option
Easier schema synchronization
Authentication Extensions
Expose HttpContext on ForgotPasswordArgs
Add hook for GetExpressionForUserGuidColumn
Fixes
Report warning for minimum level was wrong
Breaking Changes
Keep semicolon in To field as single MailMessage
Changes email parsing behavior
Maintenance
AppHarbor no longer exists (removed references)
Consistent Tag properties across system
Provide explicit cast to PO[] for AsDetail attributes
September 2024
New Features
ExecuteBatch API
Initial ExecuteBatch and split ExecuteQuery implementation
Handle GetPersistentObject, GetQuery, and ExecuteAction in batch
Handle step assignments with DynamicAssignment
TranslatedString Enhancements
Added TranslatedString.IsValid
Better validation for translations
LabelHelper
Added LabelHelper for consistent label management
Centralized label generation
RavenDB Source Generator
Provide attributes for the source generator
Better code generation support
Fixes
Detail attribute loading after save of new object
Handle invalid sorting in .NET Core
Fixed issue #356
Maintenance
Performance: Prefer JsonPoolConvert usage
Compiler optimize unused ApplicationInsights
Updated packages
August 2024
New Features
Repeating Jobs
Expose IRepeatingJobManager
Added RegisterJobAsync method
DataType Support
Support [DataType] attribute
Better validation and UI hints
Settings Builder Extensions
Added ISettingsBuilder.MultiString/Custom
More flexible settings configuration
Updatable Logs
Added IUpdatableLog.Delete
Better log management
Web Application Integration
Added UseVidyano directly on WebApplication
Simplified startup configuration
Query Column Overrides
Added ColumnOverrides for GetQuery request
Customize query result columns
Fixes
AsReadOnly setting didn't work for DataType Password
Missing DataMember attributes
Missing reserved web2 words
Maintenance
Expose StartupErrors for manual invocation
Updated documentation
Updated packages
July 2024
New Features
Memory Diagnostics (#374)
Add memory information to diagnostics
Better monitoring of application memory usage
Log Hashing (RavenDB) (#375)
BREAKING: Added MessageHash to Raven logs
Enables deduplication and better log analysis
Query Sorting (#377)
Allow SortOptions to be passed to GetQuery
More flexible query result ordering
Date Handling (#376)
Improved invalid date handling with tests
More robust date parsing
Description Attributes
Read [Description] attribute for custom actions
Better auto-documentation
Fixes
BREAKING: Logs_Search index was wrong
Missing alias in SQL statement for IsUserAuthTokenRevoked (PostgreSQL)
Added BinaryFile implicit cast to string and TryParse
Easier file handling and conversion
RavenDB Query Helpers
Added IRavenQueryable GetSum helper
Simplifies aggregate queries in RavenDB
PersistentObject Enhancements
Added PersistentObjectTypeName helper
Added POA.Actions for accessing available actions
Hide Edit/New/Delete lines on PO Rights detail query when not needed
Fixes
Ignored disposed DatabaseConnectionState for RavenDB
Ignored ConnectionResetException in custom API methods
Fixed calling RefreshOperation with only type name
Maintenance
Updated copyright year to 2024
Updated NuGet packages
Added XML documentation comments
Note: Commits marked with (test) have been excluded from this changelog as they are internal testing commits.
5.36.0+5338103
Tuesday, April 17th, 2018
Features
Added GetTextSearchColumnsForValue method to limit the columns to use depending on the searched value (i.e. 2018 should only search on dates and not numbers)
Added ApiMethodAttribute.TryAuthentication property to allow Basic authentication on the api method if supplied, otherwise the api method can still use custom authentication logic
Require two-factor code (if configured) for changing password or removing two-factor
Added scim hook for filtering users/groups
Added AuthenticatorService.GetCredentialType for new sign-in experience (includes new messages)
Changes
Changed default expiration for authtoken from 2/28 days to 12 hours/2 days
Changed throttle behavior for invalid passwords (defaults to 5 tries per window of 30secs and a maximum of 5 failed attempts per 10 minutes per user/ip combination)
Group/Tab: Indicates which group or tab the attribute belongs to.
Label: A translatable label for user-friendly display.
Business Rules: Associated validation rules.
Multivalue String: Allows users to enter multiple lines of text that can be reordered.
Combobox and Dropdowns: Enables selection from a predefined list, with options to add new values.
IsEmail: Validates if the input is a properly formatted email address.
argument, providing various request details.
Standard ASP.NET Core: Use the standard IResult interface for returning results, compatible with ASP.NET Core helper methods.
View Preferences: Configuring how persistent objects are displayed, such as master-detail or full-page views.
Custom Settings: Developers can create and manage custom settings, which can be fetched and set via code. These settings are environment-specific, allowing different configurations for production, staging, and development environments.
Updateable Logs: Supports appending to logs during long-running processes, allowing continuous tracking and insight into process execution.
Group Membership: Determines user group memberships and supports various authentication customizations, including header-based authentication.
Custom Contexts: Developers can implement their own Context classes if needed.
public partial class ProductActions
{
public IQueryable<Product> ActiveProducts(CustomQueryArgs args)
{
return Context.Products.Where(p => p.IsActive);
}
}
// No arguments, rule can be used as "NotEmpty"
public static string? NotEmpty(BusinessRulesArgs args, string value)
{
if (string.IsNullOrWhiteSpace(value))
return "{0} cannot be empty.";
return null;
}
// With arguments, rule can be used as "Between(0, 100)"
public static string? Between(BusinessRulesArgs args, decimal value, decimal min, decimal max)
{
if (value < min || value > max)
return "{0} must be between {1} and {2}.";
return null;
}
public partial class Import : CustomAction<ProjectTargetContextType>
{
public override PersistentObject Execute(CustomActionArgs e)
{
return Manager.Current.RegisterImport(e.Query?.PersistentObject ?? e.Parent!, accept: ".xlsx");
}
}
public partial class EmployeeActions
{
public override void OnImport(ImportArgs e)
{
var sheet = e.ReadAsExcelSheet();
}
}
[Description("""
Allows to download a file from the server.
""")]
public partial class Download : CustomAction<ProjectTargetContextType>
{
/// <inheritdoc />
public override PersistentObject Execute(CustomActionArgs e)
{
e.EnsureParent(Types.Employee);
// This will inform Vidyano to call the OnGetStream method on EmployeeActions.
return Manager.Current.RegisterStream(e.Parent);
}
}
public partial class EmployeeActions
{
public override Stream OnGetStream(GetStreamArgs e)
{
return e.GetText(e.Key, "Employee.txt");
}
}
public IResult Ping(ApiArgs args)
{
return Results.NoContent();
}
// Get a setting
var enabled = Manager.Current.GetSetting("FlagEnabled", false);
var retries = Manager.Current.GetSetting("NumberOfRetries", 5);
var url = Manager.Current.GetSetting("ExternalUrl", "https://service/api/");
// Set a setting
Manager.Current.SetSetting("LastSync", Manager.Current.NowOffset);
// Log an exception with detail information
ServiceLocator.GetService<IExceptionService>().Log(ex);
// Or as a warning
ServiceLocator.GetService<IExceptionService>().LogWarning(ex);
// Logged exceptions will contain:
// - Message/Type/Source
// - Data
// - All inner exceptions recursively
// Log
Manager.Current.Log("Message", LogType.Information);
// Will also log the User that was currently logged in
// For background jobs we can pass any user
Manager.Current.Log("Job failed", LogType.Error, adminUser);
// Updateable log
using var log = Manager.Current.UpdateableLog("Message", LogType.Custom);
// do some processing
log.AppendLine("Extra information");
log.ChangeType(LogType.Warning);
log.Prepend("Finished at ..."); // Makes it easy in the Logs view to see this part
log.Delete(); // if the log isn't relevant you could clean it up
/// <summary>Describes the type of logging.</summary>
public enum LogType : byte
{
/// <summary>An error has occurred.</summary>
Error,
/// <summary>The synchronization process has logged something.</summary>
Synchronization,
/// <summary>A security related entry has been logged.</summary>
Security,
/// <summary>A custom entry has been logged.</summary>
Custom,
/// <summary>A warning entry has been logged.</summary>
Warning,
/// <summary>An information entry has been logged.</summary>
Information,
/// <summary>A licensing entry has been logged (Legacy).</summary>
Licensing,
}
// In [Schema]Web.cs
public override void GetWebsiteContent(WebsiteArgs args)
{
args.ResponseHeaders.Append("X-Xss-Protection", "1; mode=block");
args.ResponseHeaders.Append("Referrer-Policy", "same-origin");
args.ResponseHeaders.Append("Strict-Transport-Security", "max-age=63072000");
// Disable unnecessary browser features to reduce attack surface
args.ResponseHeaders.Append("Permissions-Policy", "camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()");
base.GetWebsiteContent(args);
}
mkdir VidyanoSample
cd VidyanoSample
dotnet new vidyano
Architecture
Note: This documentation has been updated for v6. Please refer to the v6 Security - Architecture documentation for the latest information.
Groups / Rights
Functionality is driven by giving groups (application roles) specific rights to actions (e.g. Save, New, Delete, Print, Export, …). Without an explicit right for an action the user won’t be able to execute the action and the backend will throw an exception.
Query, Read, Edit and New rights can be defined at the attribute (property/column) level, all other actions can be defined at the persistent object (class/table) level.
Authentication
Vidyano application can be configured to allow multiple authentication sources which all map to users that can be assigned to groups.
Vidyano Authentication
Enabled by default, allows the usage of any custom name and password to log in. Passwords are stored in the database using a BCrypt hash. The BCrypt complexity can be configured and is increased by the framework on regular intervals (currently at 13). Will require a password with at least a length of 8 and it should not be in the blacklist (currently a list of the top 25 worst passwords and Pwned Passwords using the V2 range API), can be configured to use a different length, complexity (no longer recommended) or a different blacklist.
Password requirements are based on and
The service is used to validate that passwords don’t appear on any leaked password list. The new V2 api is used with the Range API to provide k-anonymity to check for breached password without disclosing the actual password (or even a full hash of it).
ADFS Authentication
Allows the use of an Active Directory Federation Service to authenticate the user in the application. The application can be configured to automatically put unknown authenticated users in specific group or this logic can be handled using code (to put the user in a specific group based on the returned claims). Will use the http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname claim as user name.
OAuth Authentication Providers
Allows the use of an OAuth provider (Microsoft, Google, Facebook, Twitter or Yammer) to authenticate the user in the application. Can also be configured to automatically create unknown users. Will use the email as user name.
Auth Token\
Once the user has been authenticated the server will return an auth token to the client that can be used for the next requests.
The token is a SHA256 hash composed of the following information:
Application salt
User name
User version (incremental number in the database that is increased when the password is changed or the user is disabled)
The actual IP address to check can be configured to allow switching between addresses within a specific cidr range in case the users have multiple external IP address or it can be changed using code.
Security Token
To ensure that the client works with the correct model (based on the rights) the server will generate a security token that can be checked when the persistent object is send back.
The token is a SHA256 hash composed using the following code:
The token uses a random salt to prevent any oracle attacks. All information is included so that the client can only modify the entity as it was sent by the server with only the attributes that were available. For attributes that the user has no edit rights the actual value is also used in the token so that the application can securely set these attributes on the server-side. Trying to modify any of the data will result in an exception being thrown by the backend.
\
Force Https / TLS 1.2
Vidyano will automatically redirect to https:// for certain subdomains (azurewebsites.net, apphb.com, …) and can be configured with a simple appSetting for custom domains. Enabling this flag will also enable HSTS (Strict Transport Security) which tells the browser to always go the https:// site directly even if the user tries to go to http:// to block MITM attacks.
Depending on the deployment it is recommended to only allow TLS 1.2 if possible. This can be enabled for Microsoft Azure App Services on the SSL settings tab:
Two-factor authentication
Each user can set its own two-factor code on the user settings page (available using the gear in the lower left of the application). The application can also be configured to require (force) two-factor authentication for users that are in a specific group (e.g. Administrators).\
Expiry date and time
IP address
Optionally the original user when an user is impersonated
Fixed synchronize for poa's with name that is not identical with context property name
Fixed issue with get unknown message for specific language
Fixed Next & Previous icon alignments
Maintenance
Updated to WebApi 2.1 (5.1)
Added groupname on persistent object attribute clone
Auto-apply text search filter based on propertyType
Note: 2014 was a transformative year with 280 commits introducing the Dynamic Schemas system, comprehensive charts functionality, verbose logging, password complexity management, Vidyano Mobile Client, and the beginning of the transition away from WPF support.
Show Collections/Security queries on DynamicSchema
Allow configuring of Security on DynamicSchema
Added default PersistentObject actions class for Dynamics (DefaultPersistentObjectActions`1)
Fixed issues with Impersonate when translation failed
Fixed issue with changes being made to User using Management
Fixed issue with tooltips on dialogs leaving invisible DOM elements behind
Fixed issue with SelectReferenceDialog modifying all open jQuery dialogs
Fixed caching issue after creating new dynamic schema
Fixed issue with EF6 handling transactions differently
Show Impersonate inline on Users
Added LastLogins/NewUsers chart on Users
Allow delete property on dynamic collections from code
Added createIfNotExists to GetOrCreateSchema method on public interface
Allow custom dynamic queries
Added favicon
Added Vidyano repository unique constraints
Changed NotEmpty rule to check current language for TranslatedString
Web: Include inline selectedItems for execute hook
Web: Fixed styling issue with input[type=password]
Data security to Dynamics
Validation logic for dynamic entities
Auditing and soft delete support
Fixed issue with duplicate group names
Fixed translated string issue on messages
Fixed issue with EF6 already optimizing joins
Fixed Chrome for Android scrolling issue on QueryGrid
Fixed viSearch issue when using double condition on entity
Fixed DateTimeOffset issue
Fixed issue with EF6
Fixed issue with using projected EF types
Ensure valid DynamicCollection/Property names
Don't add client routes for dynamic persistent objects
Added transaction support over DynamicCollection/Property deletes
Don't filter auditing and soft delete data for schema_Admin users
Moved auditing and soft delete data to separate tab/groups
Only expose correct attributes for PO/POA based on dynamic
Cache Schema.IsDynamic
Ensure correct TargetContext for ExecuteQuery
Expose various StringEx methods
Updated NuGet packages
Expose userCulture/userLanguage
Changed select optimizer to opt-in (Vidyano.EnableOptimizeSelect)
Log actual GetObjects (SQL + materialize)
Handle double conditions on viSearch
Ignore unsaved changes if po has no Save/EndEdit action
Show notification for unsaved changes on CancelEdit/CancelSave
Added Optimize Select feature
Expose some helper methods for handling Sort
Allow Key attribute on primary key properties
Force v5 to use .NET 4.5
Improved text search on bool, numeric, and KeyValueList
Show expires info on License PO
Hide trial notification after activation
Added option to request trial key
Added api methods (available from /api/methodName)
Added required for Remaining- and MatchingDistincts attribute
Web: changed confirmation for unsaved changes on CancelSave/CancelEdit to opt-in
Web: consistent behavior for PU's and openFirst
Web: tweaked position of labels and input
Fixed BulkEdit issue on system PO's with TranslatedString
Consistent NuGet packages
Fixed edmx warning
TypeScript definitions update
Tweaked VidyanoDbCache to use locking instead of ConcurrentDictionary
Make sure SelectInPlace uses the DisplayAttribute for sorting
Updated WindowsAzure.Storage to version 4.2
Fixed AdvancedSearch issue
Fixed issue with TriggersRefresh
Fixed issue with Word template
Fixed issue with sorting on Dynamic
Fixed QueryGrid sometimes not showing bottom row
Fixed Flags enum box with empty value
Fixed KeyValueList issue
Added IndexHtml to CustomWebController
Removed old WPF test project
Fixed null check in showNotification
Fixed issue with CancelEdit only working once for StayInEdit
Fixed issue with eg Object tampering being thrown during ExecuteAction
Fixed issue when synchronize creating duplicate PO's
Fixed issue when Logging exception before initializing logic is executed
Fixed NRE for textSearch on virtual property
Fixed issue with missing result hook for PO
Fixed issue with accent colors
Updated WindowsAzure.Storage to version 4.0.1
Updated EntityFramework to version 6.1.1
Removed some obsolete code
Don't show ACS exception information to end user
Make sure cache is updated when using Manager.CreateForUser
Added ellapsed milliseconds to verbose logging
Correctly handle added/removed attributes during refreshFromResult
Added count to spinner to prevent premature spinner removals
Call onError when onCompleted throws an exception in ExecuteAction
Show client error if refreshFromResult is called with wrong PO
Added ObjectTamperingDetection helper
Expose Parent on QueryExecutedArgs
Show messages with invalid format
Allow data filter/text search with non-existing properties
Changed QueryResultItemValue.displayValue to be both function and string
Changed luminance to +25% for light accent color
Fixed typo in message
Ignore columns that can't be filtered
Updated crawler handler with more image types
Changed behavior when getPersistentObject returns a notification and notificationType is "Error"
Fixed memory leak in resize
Fixed Word issue
Fixed repeating sections issue in Word template
Fixed issue with user rights being added twice
Added option to strip unused xml from custom xml part
Added Base64 rule on ACS symmetric key
Removed ClientEnvironment.Desktop
Removed WPF templates/icons
Fixed missing query right on Vidyano.SearchObject
Use TextSearch for AdvancedSearch
Added extra hooks for GetDistinctValues
Made extra hooks visible
Added Initialize hook on any PersistentObjectActions implementation
Only call Initialize after cache is loaded
Added Retry button to Error page
Cleanup references to query resultContainer and charsContainer (leakage)
Added total time spent on SQL Statements to profiler view
Fixed issue with log verbose not matching parent
Fixed issue with reference having displayattribute with dot not working for textsearch
Fixed submenu on IE touch
Fixed issue with filtering on reference attributes
Fixed typo in AuthenticatorService.GetFriendlyUserName method
Fixed issue with UserSession.Dispose when called
Correctly generate urls for web scraper
Include ContentDisposition header for IO7 or higher
Call registerInput on detail attribute's parent
Use same logic for ACS when user can't log in (i.e. show HTML error)
Added hook on CustomWebController to override error page
Remove server and asp.net headers
Added x-frame-options = sameorigin
Added x-content-type-options = nosniff
Added basic text filtering on LogVerbose
Added reference searching on LogVerbose
Added retry for failed LogVerbose entries (max 10)
Use Log Retention settings for WebControllerLogger
Added WebControllerLogging to Windows Azure
Compress verbose logs
Added Query Page
Added PersistentObject Page
Added flipswitch
Added attribute hooking
Added save button
Fixed query filter stay open
Fixed issue with virtual Messages/Settings showing in Management
Fixed issue with $.cookie
Don't leak UserName to Google Analytics
Use correct way of transforming web.config file
Fixed TypeScript issue when building Vidyano 4.5
Strip password from incoming data in GetApplication
Removed obsolete IE8 utf8 fix
Made CustomQueryArgs parameter optional on custom queries
Added method to update PO's attributes from ClrType
Never send unmapped properties to EF query
Fixed invalid NotMapped check
Updated to EF6.1
Tweaked locking behavior for cache updates
Sleep 4 hours instead of 1 minute for deleting old verbose logs
Added disabled as placeholder for VidyanoLogging
Give link to actual Log message when synchronizing
Force password complexity (CreateNewUser/ChangePassword/...)
Correctly call VidyanoDbCache instead of Manager.Current when possible
Updated NuGet.exe to 2.8
Added Vidyano.LoggingExcludedUserIds
Added Vidyano.LoggingExcludedVidyanoMethods
Added logging of Vidyano version
Don't log verbose for IsSystem
Don't show Log (Verbose) if not configured
Added assembly binding redirects
Fixed code mirror line separator
Added template for log verbose data
Hide empty attributes on Log Verbose
Hide empty columns on Logs verbose
Add -vi- class to content for full page queries
Changed LogsVerbose WebCode to CSS
Added StackedAreaChart
Added LineChart with focus
Added custom color scale and date/number formats
Charts as TypeScript
Server-side and client-side chart rendering
Chart selector and filters
Support for up to 20 values for bar/line charts
Added WithCumulativeValues on LineChart
Added grouping to LineChart (ByYear, ByMonth, ...)
Fixed index checking bug
Fixed reflection issue when calculating total
Fixed search box disappearing on navigation
Fixed chartSelector bug
Fixed LineChart when filtering
Fixed DataFilter issue on in-memory queries
Fixed issue with synchronize when using custom detail query
Fixed issue with calls to refresh distincts when adding or removing empty filter column
Fixed bug where chart selector is shown on full page layout while not in query mode
Fixed issue with having multiple attributes with column in single group
Fixed broken merge on POA Clone method
Fixed overflow hidden clipping chart tooltips
Fixed chart issues on EF6
Fixed chart label not being used on rendered chart
Fixed chart issues on EF6
Added MultiString Web control
Show ExecuteQuery notifications on Query
Prevent EF6 merge issues
Allow customization of Total Item (GetTotalItem method)
Correctly verify the chartSelector container is still in reference to the current query
Added safety check to chartSelector
Pass along parent in ChartArgs
Fixed issue with wrong version of d3js
Only call OnChart when calling ExecuteQuery with Top is 0
Update charts client-side
Changed behavior when getting Vidyano objects from cache
Removed wl.basic from Microsoft Account OAuth
Handle DataTinker license differently (only DataTinker schema is checked)
Added overloads to get values for children on BarChart/LineChart
Added MultiString data type
Added extra operators to POA (to string[], to JObject, to JArray, from string[], from JToken)
Fixed issue with data filter not ordering on reference attributes
Fixed empty source on Query in some cases
Added Vidyano.Service.Charts using on new POActions
Added Poll method to WebController
Keep enumerables as enumerable when using Where/Select/SelectMany on Source
Show exception when sort failed for EnumerableQueryable
Improved setting of Total value when using TotalItemArgs
Fixed issue with ServiceGateway.fromServiceString not working for unsigned types
Moved Vidyano web classes to Vidyano module
Improved vidyano.d.ts
Updated Vidyano-4.0.d.ts
Updated NuGet dependencies
Added WindowsAzure.Storage nuget package
Fixed profiler issue
Consistent API for BarChart/LineChart
Added Select/SelectMany on Source
Handle elapsedMs on profiler as int
Added header to charts
Always order line chart on date
Moved charts to Charts namespace
Updated chart color palette
Added TypeScript libraries
Opened service side Charts
Show bar char x axis
Fixed bar chart labels
Handle null/empty as name
Changed bar to use color
Added client bar chart rendering
Added filters for bar chart values
Finalized bar chart (up to 5 values)
Added submenu to chart buttons
Fixed data filter stay open
Render client side query treemap
Fixed data filter for charts
Fixed profiler ellapsed milliseconds
Fixed issue with Query argument when Query is using another PO (DB View, ...)
Fixed datafilter for inherited user actions
Fixed NullableBoolean search not working
Fixed merge issue
Fixed NRE issues
Changed New behavior to hide attributes that don't have New right
Forgot password
Note: This documentation has been updated for v6. Please refer to the v6 Security - Forgot password documentation for the latest information.
When working with email addresses as user names we can use this information to provide a forgot password functionality. By implementing the HandleForgotPassword method on the Advanced class you’ll get the “Forgot password?” button on the Sign in screen.
Best practice recommends for generating a random reset password token (ObjectEx.GetSecureRandomPassword can be used), storing the token in the user profile, emailing the user a link that triggers an api method that will verify the token and user combination. At that moment you can use the IUser.ResetPasswordNextLogin() method to trigger a password change on next login and redirecting the user to an existing logged in session.
// In [Schema]Advanced.cs
public override void HandleForgotPassword(ForgotPasswordArgs args)
{
// NOTE: Always inform for success so that we don't leak information about users
args.Notification = "An email has been sent with all the information to reset your password.";
var user = Manager.Current.GetUser(args.UserName);
if (user == null)
return;
var userHostAddress = Manager.Current.RequestMessage.GetClientIpAddress();
var token = user.Profile["ResetPasswordToken"];
if (string.IsNullOrEmpty(token))
{
token = ObjectEx.GetSecureRandomString(16).Replace("-", null).Replace("_", null);
user.Profile.SetValue("ResetPasswordToken", token);
}
var location = Manager.Current.WebsiteRoot + $"api/ResetPassword?UserName={user.Name}&Token={token}";
// TODO: Send email to user with information (password change requested, from ip, location to click, ...)
}
// In [Schema]Web.cs
public HttpResponseMessage ResetPassword(ApiArgs args)
{
var userName = args.Query["UserName"];
var token = args.Query["Token"];
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(token))
return args.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid request");
var user = Manager.Current.GetUser(userName);
if (user != null && token == user.Profile["ResetPasswordToken"])
{
user.Profile.SetValue("ResetPasswordToken", null); // NOTE: Resetting the token can be a problem if the user doesn't complete the change password prompt
user.ResetPasswordNextLogin();
var encodedUser = Convert.ToBase64String(Encoding.UTF8.GetBytes(user.Name)).Replace('/', '_');
var authToken = WebController.GenerateAuthToken(user.Name, DateTimeOffset.Now.AddDays(28), Manager.Current.RequestMessage.GetClientIpAddress()).Replace('/', '_');
var response = args.Request.CreateResponse(HttpStatusCode.Redirect);
response.Headers.Location = new Uri(Manager.Current.WebsiteRoot + "#!/SignInWithToken/" + encodedUser + "/" + authToken);
return response;
}
return args.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Invalid request");
}
Changelog 2025
August 2025
Fixes
Fixed Rules handling for string when property is TranslatedString or enum
Fixed RavenDB issue where logs couldn't be opened
Fixed IsWeb2OrGreater logic to stay in sync with Manager
Maintenance
Updated packages
Range indexer usage improvements
Documentation updates for authentication
July 2025
New Features
Logging Enhancements
Added Manager.GetLog(id) method
Direct access to specific log entries by ID
Fixes
Fixed NumberOperationsPattern not allowing != operator
Fixed Inherited not showing PO.IsReadOnly correctly
Fixed Report to use default preferKeys (bug from June changes)
Allow PersistChanges for IsValueObject if not inside AsDetail attribute
Allow sorting/filtering on valueobject detail queries
Missing template update for RavenDB PersistentObjectActionsReference
May 2021
New Features
Query Enhancements
Expose Query on PreviewActionArgs
April 2021
Fixes
Fixed issue when SeederHash is changed
Fixed issue with NewUser patch
Fixed issue #299
Maintenance
PostgreSQL: Fixed typo when removing user from group
March 2021
New Features
TranslatedString (#296)
Introduced TranslatedString type for multilingual support
Complete internationalization infrastructure
Two-Factor Authentication
Allow easier verifying of two-factor token
Dependency Injection
Use DI for Api method invocation
Use ActivatorUtilities for custom actions
BREAKING: Consistency in POActions creation with CustomActions
Fixes
Fixed issue #297
Fixed NRE when using Reference as breadcrumb on Reference
Fixed wrong order in default culture.json
Maintenance
Allow redirect inside GetWebsiteContent
Nullability improvements
February 2021
New Features
Configuration
Added DisableUserLastLoginDate config option
CSS Processing
Handle @apply for vulcanized CSS
Better CSS processing
Fixes
Fixed ArgumentNullException on Setting.GetLockedValue
Handle empty model.json with only Verbose set
January 2021
New Features
Expression Generation
Better expression generation for exclusions (fixes issue on RavenDB)
Fixes
Fixed issue #291
Multiple fixes related to assembly naming
Maintenance
Reverted Assembly name for Vidyano.Service
Pipeline improvements
Updates for Vidyano.SqlServer/Vidyano.PostgreSQL
Note: Commits marked with (test) or [skip ci] have been excluded from this changelog as they are internal testing commits.
5.38.3+a697611
Thursday, July 26th, 2018
Features
Redirect to Web2 CDN by default instead of proxying requests, will allow browser cache and even between different Vidyano applications
Cache vulcanized requests for better performance
Made all requests handling async
Make use of the System.Buffers package if it is added to a Vidyano application
Added advanced hook for handling cache updates manually (Advanced.OnCacheUpdateSaved)
Added PersistentObject.DialogSaveAction to use a different action for the default Save button on dialogs
Added AsyncCustomAction class to have a complete async flow in custom actions
Changes
Calling Manager.DeleteUser with the name of a group will no longer delete the group
Keep working with in-memory cache when CDN is not available and CDN is being proxied
Expose more information on SCIM /Groups
Fixes
Fixed issue when deleting empty group
Fixed issue with TLS 1.1/1.2 not being used for external requests
Fixed issue when invalid model.json was loaded
5.45.0+26864bd
Monday, February 10th, 2020
Features
Added Advanced search save-load
Changes
Always include name in ProgramUnitItemGroup based on DefaultLanguage
Trim user name that is passed to GetCredentialType
Expose friendly information when a FaultException is thrown in GetCredentialType/HandleUnknownAuthenticate
Fixes
Fixed issue with ExportToExcel not respecting custom column order from user
Fixed NullReferenceException when starting a legacy Vidyano application
Fixed NullReferenceException when searching on a reference attribute that uses breadcrumb attributes that aren't available (i.e. because they are hidden or disabled through security)
5.39.1+f04e696
Tuesday, August 28th, 2018
Features
Added ProjectionStringLengthAttribute to reduce the length of string columns in the projected type (i.e. to only get the first 101 characters of the Message column from the Vidyano.Logs)
Updated repository version to V60 to introduce optimized cache updates, load-balanced deployment should get a big performance increase
Added custom user schema support for SCIM
Changes
Don’t show stack traces to users that aren’t in the Administrators group (a Log-id is shown instead)
Exposed AuthenticationService.HandleUnknownAuthenticate to handle custom /Authenticate/X requests (only SAML2 is handled by default)
Exposed the IScimHandler interface for SCIM customizations
Fixes
Fixed issue when corrupt model.json is fixed on read-only deployment
Fixed threading issue which caused Options for a SelectInPlace attribute to be empty
Fixed issue that caused fallback to default sort options not working if attribute no longer exists
Storage Provider
Vidyano has the ability to store incoming and outgoing requests when the verbose logging feature is enabled. This can help for troubleshooting requests or for auditing purposes.
By default it will use the Vidyano.Logging connection string to create a blob container to store the data as block blobs.
Using the Advanced.StorageProvider property you can set your own provider that implements the IStorageProvider interface.
Example
This example will store the data inside the App_Data/Logs folder.
Vidyano contains a Vidyano.Core.External.FolderStorageProvider implementation that has gzip and encryption support.
Courier Feature
1. Overview
The Courier feature in Vidyano provides a reliable, message-based processing system built on top of RavenDB. It enables asynchronous communication between different parts of your application through a publish-subscribe pattern, supporting immediate and delayed message delivery with at-least-once guarantees.
2. Enabling the Courier Feature
To enable the Courier feature in your Vidyano application:
Register the feature in your Startup.cs file:
3. How It Works
The Courier feature works as follows:
Message Publishing: Messages are stored in RavenDB as CourierMessage documents.
Message Processing:
A RavenDB subscription monitors the database for new messages
4. Key Features
4.1 Message Delivery Patterns
Immediate Delivery: Messages are sent and processed as soon as possible
Delayed Delivery: Messages are processed after a specified time delay
At-Least-Once Delivery: Messages are guaranteed to be delivered at least once
4.2 Idempotent Messages
Messages can implement the IIdempotentMessage interface to ensure they are only processed once, identified by a unique identifier.
4.3 Message Retry
Failed messages can be automatically retried based on configurable retry strategies.
4.4 Message Expiration
Processed messages are automatically removed from the system after a configurable expiration period.
5. Usage Examples
5.1 Defining a Message
5.2 Creating a Message Handler
5.3 Sending Messages
5.4 Chain of Messages
6. Configuration Options
The Courier system can be configured in your appsettings.json file:
Configuration options:
RetryWaitTime: Time to wait before retrying subscription connection (default: 30 seconds)
MaxDownTime: Maximum period the system will be down before giving up (default: 5 minutes)
MaxDocsPerBatch: Maximum number of messages processed in a batch (default: 25)
7. Best Practices
Keep Messages Small: Store only essential information in messages.
Make Messages Immutable: Use C# record types or immutable classes.
Design for Idempotency: Ensure that processing a message multiple times does not cause issues.
8. Troubleshooting
If messages are not being processed as expected:
Check Subscription Status: Ensure the RavenDB subscription is active.
Verify Handler Registration: Confirm that your message handlers are registered correctly.
Review Message Serialization: Check that your message classes can be properly serialized/deserialized by JSON.NET.
5.32.1+0c41761
Saturday, February 10th, 2018
Features
Added Manager.OriginalUser to determine which user impersonated the current user
5.35.5+2316022
Friday, March 30th, 2018
Features
Vidyano will now throw a SaveFailedException inside SaveExisting/SaveNew/SaveDetails when it has an error
Roslyn docs configuration
Revokes all sessions when sliding sessions are enabled
Fixed issue ensuring AddTypeHint quotes value correctly if needed
Fixed IsWeb2OrGreater handling logic
Improved console logging for SchemaSynchronizer
Updated documentation with correct URLs
Created snupkg files for debugging
Vidyano.Abstractions version 6.4.0
Added readme to NuGet package
Enabled deterministic build
Don't remove request data when disposing UserSession
Fixed NRE when calling GetError with uninitialized cache
Fixed issue #241
Fixed issue #242
Don't expose database exception in GetClientData
Truncate logger entries
Test: Configure JWT key
Added query grid cell template
Allow reordering
Fixed issue when image is bigger than 512KB
Swallow exceptions from DetermineMissingUserInRequest
Test: ImageUrl changes read-only
Fixed issue #238
Allow text filter op string[] for non-EF query (#248)
Fixed issue with Web2Version setting update not being propagated
Tweaked EF profiler (using IDbCommandInterceptor)
Pass caught exceptions to profiler
Pass targetContext correctly when filtering for load entity
Fixed issue with Hasherid not working for EF POCO entity
Fixed issue when ContentProperty points to DbQuery<T>
Fixed issue with empty ProgramUnit staying
Updated packages
Nullability improvements
Better value object handling with nested support
Removed Advanced.PreCommandExecute hook
Nullability improvements throughout
Helper for reloading POA.Options for ILookupKeyValueData
Exposed CustomQueryArgs constructor
Exposed ValueObjects.IsValueObject and added TryGetRootEntity
RavenDB: Performance issue with .Include not working with .AsNoTracking
Cloudflare changes
Show installed plugins info
Updated packages
Nullability tweaks
Don't check SecurityScope for Profiler
Allow TranslatedString to be used outside a Vidyano application
Made explicit that ConfigurationManager.AppSettings[] never returns null
Nullability improvements
Fixed issue #311
Set IsValueObject correctly on detail queries/asdetail/withreference
Handle ValueObject AsDetail handling on RavenDB, single DB call for Save
Don't verbose log without VidyanoMethod
Non-generic ToProjection
Updated packages
Exposed hooks for TextSearchHandler (StartsWith/Contains/EndsWith)
Code cleanup
PostgreSQL: Fixed issue with wrong function name
Parent PersistentObject’ ObjectId/IsNew is now set before the lookup quueries are executed on reference attributes
Removed unused version override support on web2 endpoint
Added more logging information when an exception is thrown during ExecuteQuery
Implemented SCIM PUT /Users/ID
Allow SCIM PUT/PATCH /Users/ID to change user.Name
Added Vidyano.AuthTokenExpirationDevMultiplier appSetting for longer expiration during development
Keep ObjectId from newly saved entity in verbose logs
Added Reload/SessionLost client messages
Copy all attributes values to entity when saving new entity
Added detection for .NET 4.7.2 in diagnostics page (and fixed detection of 4.7.1)
Missed the notificationDuration parameter in some methods
Append random data to verbose log rowKey to reduce duplicates
Allow patch import to be used on already patched data
Fixed issue with ExportToExcel on Advanced search not returning any rows
Fixed issue with verbose logging not working if repository cache failed to load
Changed required rights for a custom AddReference query from Edit to Query
Changed logic for creating new context in PersistentObjectActions/AsyncCustomAction
Also show non-database SqlErrors to end-users (e.g. timeout)
Fixed issue that the current groups weren’t returned correctly for the current user
Give Feedback/Profiler rights if OriginalUser is member of Administrators
Log Feedback as OriginalUser
Changes
Don’t show DisableTwoFactor for users that require Two-factor
Changed new Vidyano project template with more entropy for application salt and updated the default generated files
Fixes
Fixed issue when writing custom filter for Azure table query
Added computed attributes that can be translated to database calls
Added grouping on attributes
Added IncludeCount on ProgramUnitItem to send query count to client during GetApplication
Changes
Still send profiler information (if allowed) when an exception occures
Don’t send SqlException information to client for non-admins, instead a generic database error message is shown with a log id
Use ObjectEx.GetSecureRandomString for SecurityToken salt
Allow HEAD method on /Poll endpoint
Added localNameSelector parameter for PieChart.WithValues
Expose Manager.WebsiteRoot property
Fixes
Fixed issue with verbose logging to sql server not trimming data correctly
Fixed issue when incoming user name not trimming correctly
Fixed issue when using ResetPasswordNextLogin for a user without a password (e.g. for a new user)
Fixed issue with instant search input not trimming correctly
Fixed security issue that might leak profiler information on invalid requests
Fixed issue with verbose logging only showing 101 records when db is used
Fixed issue when VPD Where handler assumed IEnumerable
Fixed issue with Edge displaying MultiLineString/CommonMark as “null” on New entity
Fixed issue with ComputeTotalItems not working for PageSize=0
5.27.0+6b9495e
Friday, October 27th, 2017
Features
Added Advanced.TryReadDataFile/WriteDataFile hook to customize loading json files from App_Data
Added QueryAction enum to define built-in actions on query that can be passed to Query.DisableActions
Added IExcelWriter.SetCell method that can also handle data type (numbers, dates, boolean, …)
Added IUser.IsEnabled/Enable()/Disable()
Changes
Changed serialization property order to make debugging of http requests easier
Added overload on CustomApiController.Json to also pass JsonSerializerSettings
Added Tag property on service objects to pass any extra data to the client
Fixes
Fixed issue with unique constraint violation not using attribute’s label
Fixed issue with PersistentObject.SaveDetails causing PersistentObject.PopulateAttributeValues to fail
Fixed issue with Query UserRight not having Filter action
using System.IO;
using System.Web.Hosting;
using Vidyano.Core.External;
public sealed class FolderStorageProvider : IStorageProvider
{
private readonly string path = HostingEnvironment.MapPath("~/App_Data/Logs");
public void Delete(AzureStorageAccount account, string containerName, string name)
{
File.Delete(Path.Combine(path, containerName, name));
}
public void EnsureExists(AzureStorageAccount account, string containerName)
{
Directory.CreateDirectory(Path.Combine(path, containerName));
}
public string DownloadText(AzureStorageAccount account, string containerName, string name)
{
return File.ReadAllText(Path.Combine(path, containerName, name));
}
public string UploadText(AzureStorageAccount account, string containerName, string name, string data)
{
File.WriteAllText(Path.Combine(path, containerName, name), data);
return string.Empty;
}
}
When a message is detected, the system finds the appropriate recipient(s)
Each recipient processes the message through its ReceiveAsync method
After processing, messages are marked as processed with an expiration time
Message Lifecycle:
Created → Waiting for Processing → Processed → Expired
Or: Created → Delayed → Waiting for Processing → Processed → Expired
Or: Created → Waiting for Processing → Failed → Retry → Processed → Expired
Handle Exceptions: Implement proper exception handling in your message handlers.
Use Message Chains: Break complex workflows into chains of simple messages.
Consider Message Expiration: Set appropriate expiration times for processed messages.
Monitor the System: Implement logging and monitoring for message processing.
Examine Expired Messages: Look for messages that have expired before processing.
Look for Exceptions: Check exception logs for errors in message handlers.
Inspect RetryWaitTime: Adjust RetryWaitTime if messages are not being retried quickly enough.
Disable Specific Message Types: Use the Courier{MessageTypeName}Disabled setting to temporarily disable processing of specific message types.
public void ConfigureServices(IServiceCollection services)
{
// Add other services...
// Register your Courier message handlers
services.AddRecipient<YourMessage, YourMessageHandler>();
}
// Regular message
public record NotificationMessage(string Subject, string Body, string RecipientEmail);
// Idempotent message
public record OrderProcessedMessage(string OrderId, DateTimeOffset ProcessedOn) : IIdempotentMessage
{
// Implementation of IIdempotentMessage.Identifier
public string Identifier => $"order-processed-{OrderId}";
}
public class NotificationMessageHandler : IRecipient<NotificationMessage>
{
private readonly IEmailService _emailService;
public NotificationMessageHandler(IEmailService emailService)
{
_emailService = emailService;
}
public async Task ReceiveAsync(ReceiveArgs<NotificationMessage> args, CancellationToken cancellationToken)
{
var message = args.Message;
// Process the message
await _emailService.SendEmailAsync(
message.RecipientEmail,
message.Subject,
message.Body,
cancellationToken);
// Configure message expiration (optional, defaults to 1 day)
args.ExpireAfter = TimeSpan.FromDays(7);
// Example of sending a follow-up message
args.Courier.Send(new NotificationLoggedMessage(message.RecipientEmail));
}
}
// Get the courier service
using var _ = ServiceLocator.GetScopedRequiredService<ICourier>(out var courier);
// Send immediate message
courier.Send(new NotificationMessage(
"Welcome!",
"Thank you for registering.",
"user@example.com"));
// Send delayed message (relative time)
courier.DelaySend(
new ReminderMessage("Don't forget to complete your profile."),
TimeSpan.FromDays(3));
// Send delayed message (absolute time)
var nextMonday = GetNextMonday();
courier.DelaySend(
new WeeklyReportMessage(),
nextMonday);
// Send idempotent message
// This will only be processed once, even if sent multiple times with the same ID
courier.Send(new OrderProcessedMessage("ORD-12345", DateTimeOffset.UtcNow));
public class OrderCreatedMessageHandler : IRecipient<OrderCreatedMessage>
{
public Task ReceiveAsync(ReceiveArgs<OrderCreatedMessage> args, CancellationToken cancellationToken)
{
// Process the order
ProcessOrder(args.Message);
// Start order fulfillment process by sending another message
args.Courier.Send(new InitiateFulfillmentMessage(
args.Message.OrderId,
args.Message.Items));
// Schedule a follow-up message after 3 days
args.Courier.DelaySend(
new OrderFollowUpMessage(args.Message.OrderId, args.Message.CustomerEmail),
TimeSpan.FromDays(3));
return Task.CompletedTask;
}
}
Added ability to disable computing of total items for queries, e.g. skipping the extra count call to the database
5.26.2+bccf416
Wednesday, October 11th, 2017
Features
Added ability to define default/cancel button index for RetryAction
5.19.0+0964f9
Wednesday, May 24th, 2017
Features
Added ability to request PO on backend using IsNew directly
5.22.1+557c11
Friday, July 28th, 2017
Features
Added ability to skip data security when using GetEntity/FindByObjectId
5.23.0+9b8b99
Thursday, August 7th, 2017
Features
Added ability to define SwaggerAttributes using Advanced.HandleSwaggerMetadata
5.20.0+95f4d1
Wednesday, June 7th, 2017
Features
Added ability to define Register PO and handle Forgot password logic ()
Added ability to disable implicit rights for Administrators group allowing for easier testing of rights (e.g. <add key="Vidyano.NoImplicitAdminRights" value="True" />)
Added ability to define cidr ranges for less strict ip check by setting the Vidyano.CidrRanges app setting (e.g. <add key="Vidyano.CidrRanges" value="192.168.0.0/16;127.0.0.0/24" />)
Added Duplicate dev action on User right and Report
Always log exceptions on Api methods
Added ability to create new users with settings directly and flag to throw exception if user already exists
Updated available type hints on attributes for Web2 client
Added .NET 4.7 detection on diagnostics page
Added some reserved words for program unit names to prevent conflicts with routes
Added new CheckDetailRules method on PersistentObjectActions that will called before trying to save a detail PO
Changes
Throw exception during OnLoad if entity is not found instead of setting notification
Don’t store new group in patches, added notifications to describe recommended behavior
Updated DocumentFormat.OpenXml NuGet dependency to 2.7.2
Updated Newtonsoft.Json NuGet dependency to 10.0.3
Made CommonMark dependency optional, if you are not using this you can remove the NuGet dependency
Fixes
Fixed issue when deleting PO that had detail queries on another PO
Fixed issue when using <= on date time
Fixed issue when using space to separate hour part
Fixed issue with invalid sort options for reports
Fixed issue when saving query filters with NoDatabase enabled
Fixed issue when a native client connects to a production environment
Fixed issue with custom query that has another entity type not using DefaultPersistentObjectActions class
Fixed issue when adding a new language and no microsoft translator key was defined
Fixed issue when renaming Persistent Object on an application with verbode model enabled
Changes
Strip comments from vulcanized html for Web2
Made ImageUtils class public (can validate image, generate QR code, …)
Don’t show New Query UserRight on Custom Actions’ Rights query
Show more information from DbUpdateException and UpdateException in GenerateMessage
Changed logic for converting decimal to service string to match client
Updated signature of RefreshOperation.Query to reflect that it can be either a name or an id
Refresh queries with user rights when saving or deleting user right
Changed WebController.GenerateLocalAuthToken to use same long expiration as staysignedin
Fixes
Fixed issue when ACS was used through proxy
Fixed issue with user created through CreateNewUser not loading groups
Fixed issue with AutoCreateUsersInGroup having invalid options after a refresh
Fixed a caching issue when a group is renamed that an user can’t be added to that group
Fixed NullReferenceException when using HttpHandler directly with WebController with null HttpContent in request
Fixed issue with Manager.DeleteUser
Fixed issue with ExecuteAction through form using 100% cpu for very large requests in chrome
Added Advanced.HandleUnobservedTaskException hook
Use TypeConverter when converting to and from a service string
Allow changing of IUser.Profile
Changes
Don’t block application start when cleanup of CacheUpdates/Logs fails
Respect developer CanSort=false options for existing user sort options
Allow Async suffix for custom api methods
Don’t show outdated model message when model hash is IGNORED
Fixes
Fixed issue with Word.Generate when passing IsNew PO trying to add queries
Fixed issue with AzureTableQuery in Release builds
Fixed issue with IUser.Profile not returning correct data
Fixed issue with unknown user id on report throwing NullReferenceException
Fixed issue when AutoQuery is enabled during OnConstruct(query, parent)
Added Advanced.BlacklistedPasswords per Microsoft Password Guidance for improved security
Changes
Show more information when repository metadata upgrade failed
Updated XML comments to indicate that GetEntity/FindByObjectId will use data security
Don’t use data security when loading entity for read-only reference attribute
Increased default BCrypt complexity to 13 (will rehash passwords on first use)
Changed default Password Complexity setting for new projects to None as per Microsoft Password Guidance
Fixes
Fixed issue with distincts on lookup query showing wrong values
Fixed issue with new CheckDetailRules failing for New entity
Fixed issue with Random not being thread safe
Fixed issue with circular group memberships
Added support for using continuation tokens on custom queries
Changes
Updated XML comments to explain which claims are used for UnknownUser
Removed obsolete code to use pages for querying instead of skip/top
Fixes
Made sure that filters are included correctly for queries that are added during OnLoad
Fixed issue with Security page in NoDatabase mode trying to use database
Fixed issue with not being able to create new feedback
Changes
Changed ToServiceString for enums to use default ToString (allows undefined enum values to be converted to numeric value)
Updated WindowsAzure.Storage NuGet dependency to 8.0.1
Show better exception when sorting fails on custom IEnumerable query
Fixes
Fixed issue when migrating repository to new semantic version
Fixed issue when using bulk-edit on PersistentObjectAttributes
Fixed issue when using bulk-edit on UserRights
Removed DB call when filtering on reference attribute
Computed attributes
This information is still applicable to v6, for the code snippet, the CustomerActions class should be partial and the base type is not needed.
Computed attributes can be used as an alternative to views but still keep the same performance. By defining the expression for a computed attribute Vidyano can make sure that the expression is translated by Entity Framework to the correct sql code.
Usage
Computed attributes should be defined in the static Initialize method of the specific Persistent Objects’ Actions class and added manually as an attribute with the correct mapping. All computed attributes will automatically be flagged as read-only.
Once configured they can be used to sort, filter (with distincts) or group on. They can be shown in a query and when loading existing entities.
Remarks
Only valid EntityFramework expression can be used if the code needs to be translated to sql (e.g. no custom extension methods)
This is kept for informational purposes as this no longer applies to v6 projects.
Prerequisites
Downloads
Installation
Extract and run the Sample database installer to deploy the database to your local SQL Server. This tutorial assumes that you keep the default name for the database "MyCRM".
Tutorial
Step 1: Creating a new Vidyano Project
Launch Visual Studio 2017 or higher. From the File menu, select New ▶ Project.
From the templates on the left, select Visual C# ▶ Vidyano.
Choose Vidyano Application,give your project a Name and click OK.
Step 2: Name and protect your new application
Give your App a Title and provide an administrative Password to secure the backend. Make sure to pick a secure password.
Click Next to continue.
Step 3: Select the target database
On this wizard step you need to select the database that holds your application data.
Click on the Browse (...) button next to the Connection String input field.
Select the MyCRM database that you installed in the prerequisites step of this tutorial.
Click OK.
Click Next to continue.
Step 4: Select the repository database
Vidyano will store some metadata in repository tables. Select the database where these tables will be created.
By default the connection string above will be the same as your target database, in this case MyCRM.
Optionally you may also select a separate database to store the repository data as to not make any changes to the target database that may be used by other applications.
Click Go ! to continue.
Step 5: Let Vidyano set up your application
At this point, Vidyano is setting up your project.
During set up you might get a message dialog asking if you want to search for TypeScript typings, you can select No.
Step 6: Launch your newly created application and sign in
Press ctrl+f5 or click the ► button on the toolbar to start your application.
Use admin as your user name and the password you entered in step 2.
Step 7: Add a menu item
Now that you are in, let's add a menu item to see the customers on the database.
On the menu, click Add menu item.
Select Customers and click OK.
Wait for the application to reload and click Customers.
Congratulations, you just created your first Vidyano application!
Added option to keep selection on query after refresh for custom action (requires Web2 1.10 or higher)
Added ApiMethodAttribute to control if manager is required or not
Fixes
Fixed issue with invalid csv being generated
5.14.1+ec0dbd
Monday, April 3rd, 2017
Features
Added reference source file for commonly used methods inside the PersistentObjectActions class. Installing the latest NuGet package will add an PersistentObjectActionsReference.cs file
Added extra methods on PersistentObjectActions base class to handle common scenarios without having to overwrite the complete methods (SaveNew/SaveExisting/OnDelete/…) ()
Changes
Changed diagnostics page to also show web2 version information for websites
Ensure that repository always has all the system settings
Fixes
Fixed issue with correct exception not being shown when RepositorySynchronizer failed on project with NoDatabase enabled
Vidyano can be configured to use Azure AD as an authentication provider. In combination with the SCIM feature to provision the users and groups you could use the Azure AD to completely control your users outside the application.
Configuration
You’ll need to set the Single Sign-on Mode to SAML-based Sign-on.
For the URLs you should use the url of the application for Identifier and followed by Authenticate/SAML2 as Reply URL:
The Configure button at the bottom will give your the correct settings (SSO Service Url and Base64 Certificate) that you need to use on the Security page.\
Tweaked new website template to use https:// for google fonts url
Tweaked new webcomponent template to remove obsolete content tag
Allow user registration
Note: This documentation has been updated for v6. Please refer to the v6 Security - Allow user registration documentation for the latest information.
On the Security page you can configure the PO that should be shown and the application group for the user rights. For most applications the Register PO will be a new virtual Persistent Object with at least an email address (username) and password attribute. The following code shows an example POActions class for the Register PO.
public class RegisterActions : PersistentObjectActionsReference<AdventureWorksEntityContainer, object>
{
public override void OnSave(PersistentObject obj)
{
if (!CheckRules(obj))
return;
var userName = (string)obj["Email"];
if (Manager.Current.GetUser(userName) != null)
throw new FaultException("That user already exists. Use the forgot password functionality to reset your password.");
Manager.Current.CreateNewUser(userName, (string)obj["Password"], profile: new Dictionary<string, string> { { "Registered", "self" } });
obj.AddNotification("You can now login using your email and password.", NotificationType.OK);
}
}
The SCIM standard was created to simplify user management in the cloud by defining a schema for representing users and groups and a REST API for all the necessary CRUD operations. See spec
Example
To enable the SCIM end-point Vidyano will require an authenticated request, the passed bearer token will need to be checked in the AuthenticatorService class. The easiest way would be to provide a single custom setting that contains the token so that it can be checked.
Other scenarios could be created by storing multiple tokens in the database.
Azure AD
Azure can be configured to sync the AD users with your Vidyano application:
Tenant URL is the url of the application (e.g. for the demo application the tenant url is https://demo.vidyano.com/ )
For the mapping we recommended the following settings:
Groups
Made SwaggerPathAttribute Path and Operation property public
Prefer alwaysStrict tsconfig
Skip new PO in synchronize if type already exists in another schema
Fixes
Fixed issue with rights for query not being removed when query was deleted
Fixed issue with enum options not showing for nullable enum
Fixed issue with IsNew PO not resetting attributes when an AsDetail attribute failed
Also log api method name in verbose logs
Made PersistentObjectAttribute.ToolTip setter public
Manager.GetUser returns null for null or empty name
Allow setting of response headers when serving index.html
Fixed issue with PersistentObjectAttributeWithReferenceBuilder not saving
Fixed issue with Security page when Register PO is deleted
Fixed ArgumentNullException when saving new User without setting username
5.29.3+30608c3
Thursday, December 14th, 2017
Features
Updated reports to define minimum required access level, new signature based option using HMAC256 and logging/disabling of compromised report for maximum security (Reports help)
Added InstantSearchArgs.AddRepository method for easy instant search on repository
Changes
Don’t log outgoing content for GetReport/Api in verbose logs
Fixes
Fixed multi-threading issue when using IUser.UpdateLastLoginDate
5.10.2+a3acd1
Thursday, March 2nd, 2017
Features
Introduced local cache for Web2 CDN requests and informing of client that the version has changed (can be disabled using the Vidyano.DisableClientVersionCheck app setting)
Changes
Updated CommonMark.NET NuGet dependency to 0.15.1
Fixes
Fixed issue with select all not working when adding queries to program unit
5.15.2+5ed89a
Thursday, April 13th, 2017
Features
Added Vidyano.Core.External.AzureStorageConnector helper class for common Azure Storage scenarios.
Changes
Removed Windows Azure NuGet packages in favor of custom implemented REST calls for Verbose Logs. Existing projects will keep the NuGet packages installed but can be removed if they aren’t used.
Removed fixed dependency on Jurassic library, Vidyano application can now remove this dependency unless they want to use the server side javascript functionality.
Don’t show custom exception message for foreign key SQL error 547
Fixes
Fixed initialization error for new projects
5.8.0+aab7d8
Wednesday, February 8th, 2017
Features
Added hook Advanced.PostNewFeedback which is called after a new feedback has been logged
Changes
Removed QueryResultItem.Breadcrumb
Fixes
Fixed issue when saving Settings on SingleInstance
Fixed issue when using Manager.GetPersistentObject not passing correct ObjectId when changed
Legacy v5.x
Old documentation for Vidyano v5 which was based on .NET full framework (4.8).
Some content will still be relevant but all parts related to ASP.NET (i.e. HttpResponseMessage or HttpContext) will need to be rewritten with ASP.NET Core alternatives (i.e. IResult, IActionResult, HttpRequest, ...). All parts related to EntityFramework6 syntax will need to be rewritten using EFCore syntax (mostly namespace changed).
Changelog 2018
December 2018
New Features
Query Projections
Added QueryExtensions.ToProjection
Better query projection support
Configuration
Use DbConfiguration for VidyanoDbContext
Always use named connection string
Fixes
Fixed issue #237
Fixed issue #218
Ignore various WebSocket exceptions
Maintenance
Made ApiArgs.Version writeable
Don't use ApiController.Request property
AI improvements
GroupingInfoArgs comment change
November 2018
New Features
Performance Optimizations
Optimized POA constructor
Optimized BulkConstructPersistentObjectAsync
Optimized IncludeFilters logic
User Communication
Added SendData to User for sending data over websockets
Tweaked IUser.SendData to provide more information
Loading Strategy
Better LoadingStrategy.IncludeReferences handling
Expose LoadEntityByObjectIdArgs.Included as ISet
Settings
Added Advanced.IsSettingValueValid
Use Setting.DataType
Fixes
Fixed issue #226
Fixed issue #233
Fixed issue #234
Fixed issue with impersonated user not having enough viAudit rights
Maintenance
Added ITargetContext interface
Profile precision changed to 0.01ms
Made PO.GetDisplayAttributeValue synchronous
October 2018
New Features
Loading Strategy
Added PO.LoadingStrategy
Cache LoadingStrategy logic
Query Features
Added POA.OptionalColumn
Added IQueryable.FilterByObjectId
Advanced Features
Added Advanced.LoadEntityByObjectId
Added Manager.HasRepositoryConnection
Fixes
Fixed issue #220
Fixed issue with circular PO reference
Only send values for columns that are defined after QueryExecuted logic
Maintenance
Ignore ReplaceSensitiveUrlPart if Uri is empty
Optimized Include path for DbQuery/ObjectQuery
Saml2.0 tweaks
September 2018
New Features
Audit System (vi-audit)
Added vi-audit functionality
Added dummy Placeholder system PO
Tweaked vi-audit to use Placeholder PO
Job Scheduling
Made JobSchedules a system setting
Fixed RepositorySynchronizer to fix non-system setting
SAML 2.0
Added hooks for Saml2.0 processing
Detect ScimHandler implementation
Fixes
Fixed issue with new RepeatingJob not triggering
Fixed issue with impersonated user not having enough viAudit rights
Always clean up UpdatingMetadata flag
Maintenance
Set Import PO as OpenInEdit
Profile CreateUserSession creation
Replace LogVerboseData's authToken with expiration info
Return AuthToken as header when received as header
WebException can have null Response
Fixed issue in .NET example in reports doc
February 2018
New Features
Two-Factor Authentication
Added Group.TwoFactorRequired
Allow TwoFactorRequired on system groups
Don't show DisableTwoFactor for user that requires Two-factor
Sensitive Data
Is sensitive flag on attribute and query column
Flag Vidyano User attributes as sensitive
Add IsSensitive to sensitive system settings
Reporting
Added support for tsv reports
Allow $where for reports (#150)
API & Security
Added viRemovePassword
Added Setting.Description
Added IExceptionService.LogWarning
Expose Path/Operation on SwaggerPathAttribute
Fixes
Fixed issue when deleting attributes that would remove unrelated columns
Fixed issue with Feedback misusing IsReadOnly
Reset attributes when SaveDetails fails
Maintenance
Missing translations
ServicePointManager changes for Web2Cdn
Keep PO.IsReadOnly logic when New/BulkEdit/Delete is called directly
January 2018
New Features
API Security
Added ApiArgs.IsValidSignature helper method
Added diagnostics types info
Authentication
Sliding login rate limiting (#136)
Word Processing
Added Word.ConvertToPdf helper
SCIM
SCIM tweaks
Better SCIM support
Fixes
Fixed boolean logic for hidden attributes/detail queries
Maintenance
Updated release notes for 5.30.0
Copy-paste issue for SCIM doc
Set Default QueryLayoutMode to MasterDetail for new projects
Note: 2018 was a major year for security enhancements with two-factor authentication, sensitive data handling, online password blacklist checking, and the introduction of the vi-audit system. Performance optimizations and SCIM support were also key focuses.
5.37.1+3fd7ebea
Wednesday, July 11th, 2018
Features
Added explicit UnabletToLoadEntityException (requires the System.ServiceModel namespace, latest Visual Studio extension will add it for new projects)
New Feature - Improved initial cold-start verbose model loading by reading them as parallel (can be disabled by setting the Vidyano.ModelLoaderMaxDegreeOfParallelism appSetting to 1)
New Feature - Added in-preview UserNotifications (repository version has been increased to 59)
New Feature - Added extra security layer for entities using an int/long PK by using using per entity salt
New Feature - Added implementation for a custom IStorageProvider named FolderStorageProvider
New Feature - Added support for Azure Application Insights by adding extra information to the operation names (can be disabled using the Vidyano.DisableApplicationInsights appSetting)
New Feature - Added support for providing extra search parameter when getting column distincts
New Feature - Added helper method on Manager.LogEntry to hide sensitive information from urls (i.e. token passed to api)
New Feature - Made repository schema forward compatible allowing versions starting from this version to connect to repository that are using a newer version
New Feature - Added support for using “master” as Web2 version which will use the latest commit as web2 client (for testing purposes, not supported for production environments)
New Feature - Added throttling when too many UnableToLoadEntityExceptions are thrown by a single user
Include original stacktrace when logging EF exceptions
Fixes
Fixed AmbigiousException on viSearch
Fixed issue with web2 cdn proxy on Owin hosting
Fixed issue when multiple instance tried to update the same repository (load-balancer first run for new version)
5.6.4+151e2e
Wednesday, January 18th, 2017
Features
Added PO.RemoveAttribute/AddQuery/RemoveQuery
Added support for Cognitive Services token for translations
Added ITranslationService
Added ?lang=CODE support for reports
Changes
Use IDbSet/IObjectSet to discover context property
Increased entropy for new report tokens
Fixes
Fixed issue with new language being kept on error
Fixed allow bulk-edit detection when working with base POActions class
Fixed issue with new Data Type not saving correctly
Actions classes
This information is still applicable to v6
This page provides some common scenarios to use the PersistentObjectActions class.
Soft Delete
By default, Vidyano will tell Entity Framework to delete an entity from the target context when the end user uses the Delete action. We can override this behavior so that the entity is not actually deleted but only marked as deleted (e.g. disabled, not active, obsolete, …).
Cascade Delete
Another common scenario is to delete related entities when a master entity is deleted (in most cases this can also be done on the database using cascade delete on the foreign key).
Auditing
Setting audit attributes can be easily implemented by using the UpdateEntity method to set the attributes.
External services
If we need to inform another external service about new or updated entities we can use the following code.
5.31.2+c8aabb2
Monday, February 5th, 2018
Features
Added column to show which users have Two-factor enabled and “Disable two-factor” action for admins to unlink Two-factor on a user
5.18.0+de3495
Features
Moved legacy old Web code to separate Vidyano.Service.Legacy NuGet package
5.8.1+67bcab
Monday, February 13th, 2017
Changes
Changed cors handler to use * for allowed origin
Labels
This information is still applicable to v6, for the code snippet, the Manager.Current.GetTranslatedMessage("Disable") can also be replaced with Messages.Disabled
For custom actions a developer can choose the label that should be used, but for the system actions like Save or Delete the labels have always been fixed for an application. The ActionLabels feature allows you to change the Label for the system actions using code.
Example
Best Practices
Note: This documentation has been updated for v6. Please refer to the documentation for the latest information.
If your deployment allows for configuring settings outside of the source code (e.g. the Application Settings tab on Microsoft Azure App Services) then this can be used to configure a set of application settings that even the developers won’t have access to.
Configure another ApplicationSalt (via the Vidyano.ApplicationSalt app setting)
Overriding Vidyano Settings
This information is still applicable to v6 but you should use the .NET core related configuration providers, so any of the configured providers can be used (appsettings.json, environment variables, user secrets, ...), the key to set will be Vidyano:Setting e.g. Vidyano:MicrosoftTranslatorAppId
Vidyano has always used 2 places to store settings, the web.config appSettings section for settings that required the application to restart, and the Settings repository table for settings that can be changed at runtime.
This new feature allows you to override the settings stored in the Settings repository table using the web.config appSettings section. This can be used for system settings and custom settings.
Security
Note: This documentation has been updated for v6. Please refer to the documentation for the latest information.
Updated DocumentFormat.OpenXml (reverted to 2.7.2 for compatibility)
Updated Newtonsoft.Json to 12.0.1
Updated NuGet packages
Builder changes
Optimized IsAllowed checking
Performance improvements throughout
Fixed NRE when Sorting on reference property with invalid DisplayAttribute
Fixed issue when saving new DataType
Extra profiling info during different Construct phases of PO
Skip logic faster for attributes that aren't used anyway
GetGroupingInfo hook
Split GetObjectAsync/GetObjects
Also update AI operation name for GetPO/GetQuery during exception
Set empty Actions array for LightConstruct Query
Also flag notification as read when archiving
Ensure POActions are disposed
Ensure we copy data from AggregateException when logging exception
Chart tweaks
Also log method that was used for a failed request
Strip zero width spaces from user names
HandleUnknownWebsocketMessage hook
Show extra groups that aren't in the security.json file
Force ExportToCsv to use BOM
Obsoletes clean up
Ignore I/O exception from WebSocketException
Added Manager.GetLogsSince
Handle empty ObjectId for viAudit
Allow adding of viAudit UserRight
Persist changed attributes after unchanged
Tweaked Height for LogVerboseData Data attr
Use C# 7.2
Fallback to default sorting when sort fails
Fixed issue with custom AddReference action needing Edit rights
Don't reuse ObjectContext for DbQueries
Updated docs
Changed logic for creating new context in POActions/AsyncCustomAction
Added ActionLabels docs
Also show non-database SqlErrors to end-users
Show error when viRestartApp failed
Don't use ReadContext when executing Vidyano queries
Removed duplicate right
Diagnostics: Handle case where GenerateMessage throws a ValidationException
Added WebsiteArgs.Redirect method
Enabled applicationInitialization
Fixed issue #199
Fixed issue #202
Fixed issue #204
Fixed issue #205
Fixed issue for detecting 4.7.1, added detection for 4.7.2
Fixed model load for invalid query columns
Fixed issue with handling PUT request (SCIM)
Fixed issue with caching during QueryResultItem reflection
Fixed caching issue logic on QueryResultItem property
Don't show stack traces to end-users
Redirect to Web2 CDN by default instead of proxying the requests
Replace all web2/* imports (except vulcanize) with direct cdn links
SqlDependency logging and cleanup
Don't use JsonPoolConvert for VisualStudioIntegration
Use WebsiteRoot in docs
Made System.Buffers usage opt-in
Ignore some WebSocket related exceptions
Invalid usage on ReportService when System.Buffers is not available
Added JsonPoolConvert.DeserializeObject
SCIM: allow PATCH/PUT user.Name
Missing notification duration in some methods as parameter
Fixed issue when getting SAS for blobName with special characters
Don't allow groups for Manager.DeleteUser
Renamed AzureAD to SAML2
Skip "EntityFramework: " prefix for generic log-id message
Make sure we update the cache when verifying authToken
Skip total/count/chart for Report/Excel/Word
Don't log GlobalSearch parent as IsSystem entry
Fixed issue with Web2 version setting not allowing http anymore
Correctly suggest custom query methods
Allow Search parameter for QueryFilter.RefreshColumn
Added helpers to replace sensitive url information
AI: ExecuteAction operation suffix should be set sooner
Added missing references in default new Vidyano project
WIP #179
Fixed Add menu not working when opening solution directly #179
Made Builder compatible again with VS2015
Updated Azure Blob Service Rest API version
Always allow TLS 1.1 and 1.2
Improved Web2Cdn speed
Set parent IsNew/ObjectId before calling OnConstruct for POAWR
Removed version override support on web2 endpoint
Add logging information to ExecuteQuery when an exception is thrown
Fixed projected type check
Updated security docs
Cache DynamicBase referenced type lookup
Use ProjectedType iso ReferencedType attribute
Added hook to handle custom path for patch user replace operation
Show New feedback as dialog
Try to use browser acceptlanguage for Sign in screen
Don't log ConnectWebSocket in verbose logs
Duplicate TS definition
Added FolderStorageProvider class
Added UnableToLoadEntityException
Fixed issue with #176 not displaying correctly on diagnostics page
Fixed Web2 issue with Owin hosting
Fixed issue with loadbalancer when trying to add missing settings
Added SCIM User/Group filtering
Allow custom sql errors to be shown to end-users
Verify two-factor after checking password
Also filter SCIM get group
Perf change for cleaning up vidyano logs
Don't get computed attribute for IsNew if no explicit New visibility
Authenticate should update cache first
Don't double save new feedback
Test code prefer ACS for enabled user with no password
Security docs update
Use PO Type for UnableToLoadEntityException if label is empty
Allow custom label/objectId for UnableToLoadEntityException
Made POA.DisplaySum public getter
Include original stack trace for EF exceptions
Added LoadBalancer tester project
Updated ConfigureAwaitChecker.Analyzer dev dependency
Parallel model loading
Added LoginArgs.HasSensitive
Added support for online password blacklist check
Changed CheckOnlinePasswordBlacklist to opt-out
Fixed issue #171
Fixed issue #108
Fixed issue when verbose logger in database received invalid content
Fixed issue with ResetPasswordNextLogin not showing password attribute
Fixed issue when saving existing filter
Fixed issue with VPD on POAWR using enumerable source
Log auto-resume exceptions as Warning
Always return a HttpResponseMessage
Increase pwnedpasswords api timeout to 10s
Added extra reserved words
Default usings for [Schema]Web
Added extra help message when trying to save new virtual PO
Hide Advanced ACS methods
Validate actual password change for ResetPasswordNextLogin
Attach failed sign-in log to user when user exists
Consistent EOL for all files
Expose user parameter in Manager.Log
Ignore TaskCancelledException in Web2Cdn.CacheVersion
Minimize timing attacks against unknown users
Trim incoming userName
Throw SaveFailedException when OnSave fails
Handle ResetPasswordNextLogin for users without password
Throw SaveFailed in SaveExisting/SaveNew/SaveDetails
Ensure profiler has correct value when returning
Trim instant search input
Added POA.CanGroupBy
Don't expose sensitive database information
Use secure random string for salt
Allow HEAD /Poll
Added option to Include count for Query PUI
Added localNameSelector for PieChart
Handle = null difference between DynamicLambda and EntitySQL
Expose current application root uri
Don't expose SqlException to non-Administrator users
Hide Code attribute when disabling newly two-factor
Actually fixed #108
Handle sorting of TranslatedString on DB
Required SQL for generating dummy function
Also pass parent correctly when checking VPD
Manager.Current.User can be null
Skip MemberOf check if not cached
Move GetGroupingInfo to POActions
Fixed issue with ComputeTotalItems not working for PageSize=0
Fixed cast issue in GetGroupingInfo
Changed default expiration from 2/28 days to 1/2 days
Added ApiMethodAttribute.TryAuthentication
Added PO.IsBreadcrumbSensitive
Flag application as having sensitive data
Also flag UserHostAddress and RequestId as sensitive
Made POA.ToolTip settable
Fixed POAWRBuilder not saving
Fixed issue #152
Fixed issue with OnNew flagging PO as IsBreadcrumbSensitive
Fixed ArgumentNullException when saving User without filling in username
Some exceptions can be ignored
Expose WordprocessingDocument in Word.Generate V2
Ensure Manager is initialized for ACS/OAuth/Authenticate request
Hide System.Linq/System.Collections.Generic namespace in typediagnostics
Added notification on New User to inform to which group it will be added
Reverted back to EF 6.1.3
Added ObjectEx.GetSHA512
Fixed issue with OAuth/ACS calling Advanced.GetClientIpAddress twice
Added docs favicon
Fixed invalid seed SQL script
Profiler changes
Added Manager.OriginalUser
Keep OriginalUser when impersonating again
Fixed custom azure table queries
Log feedback as original user
Tweaked default builder classes
Updated Builder
Only need to add extension once
Synchronize changes
Log api method name in verbose logs
Remove user rights when deleting query
Use new height typehints
Show enum options for nullable enum
Prefer GetAwaiter().GetResult() instead of .Result
Removed unneeded LINQ call
Hide some obsolete classes/properties
Let Manager.GetUser return null for null or empty name
Handle images as binary
Updated security docs
Added support for online password blacklist check
Allow setting of response headers for index html request
Check all groups instead of only direct groups
Removed obsolete migrations
Support UserName/AuthToken in Authorization header
Fixed issue when using bulk-edit on Users
Fixed issue when using bulk-edit on UserRights
Fixed issue when using bulk-edit on PersistentObjects
Don’t send HSTS header when running on localhost
Added Group.TwoFactorRequired to indicate that all users in that group require Two-factor authentication
Added “Remove password” action on users with a password so that they can only login using external authentication providers (or impersonate)
Added optional Setting.Description to describe the usage of the custom setting
Added Word.ConvertToPdf helper (requires key from 2sky)
Added ScimCredentials.AllowedOperations to disable specific scim operations if needed (i.e. allow a token to only read user/group data but not modify it)
Added new /diagnostics/types helper page to determine what .NET types/methods are used for custom queries/custom actions/POActions
Switched to an ip based throttling for checking password during authentication (1 try per second) (app setting Vidyano.MaxLoginTries, e.g. 1/5 for 1 try every 5 seconds or 10/1 for 10 tries every second, use 0/0 to disable throttling)
Added ApiArgs.IsValidSignature method to check for same AuthorizationSignature based authentication as reports
Added notification when creating new User to inform to which group it will be added
Added string.GetSHA512() extension method
Changes
Expose WordProcessingDocument on WordArgs
Setting PO.IsReadOnly in Management part will now also check this for New/BulkEdit/Delete action calls
Removed override on ServicePointManager.SecurityProtocol in favor of default .NET configuration
Changed User settings screen to require current two-factor code when disabling two-factor
Changed Default QueryLayoutMode setting to MasterDetail for new projects
Reverted EntityFramework NuGet dependency back to 6.1.3
Fixes
Fixed issue when removing an attribute that would also remove unrelated columns with the same name
Fixed issue with new sync option for hidden attributes and detail queries
Ensure Vidyano is initialized when it receives authentication requests (OAuth/ACS/…)
Fixes
Fixed issue with web2 vulcanize resource when it only has read access
Fixed issue with Regenerate token action being shown on read-only report
Fixed issue with Read right being required for OnPreviewAction
Fixes
Fixed issue with exception in custom Web class constructor not being logged correctly
Always show DisableTwoFactor action in management for users with Two-factor enabled (can be used to reset two-factor token)
Expose Query.GroupedBy
Expose PersistentObjectActions.CheckDetailRules in reference implementation
Return false when ValidateAuthToken is called with empty userName (instead of exception)
Added ServiceWorker flag as possible ClientEnvironment
Expose hook for custom paths during scim patch user operation
Show New feedback as dialog
Try to use browser acceptlanguage for Sign-in screen (during GetClientData)
Support AccountSAS for AzureStorageConnecto
Export ExecuteAction’s parameters on ChartArgs
Renamed AzureAD authentication provider to SAML2
Skip “EntityFramework: “ prefix for generic log-id message
Skip total/count/chart for Report/Excel/Word
Extended scim support to provide more correct information ($ref/location)
Updated Azure Blob Service REST api version to 2017-11-09
Fixed issue when invalid Web2 version was used in settings by validating version before saving
Fixed issue when getting SAS for a blobName with special characters
Fixed issue with invalid custom query methods being suggested
protected override void PopulateAfterPersist(PersistentObject obj, Customer entity)
{
base.PopulateAfterPersist(obj, entity);
var wasNew = obj.IsNew; // The entity will have the correct DB primary key at this moment
ExternalService.PostCustomer(wasNew, entity);
}
Set the DiagnosticsToken to a secure random string (Vidyano.Diagnostics token)
Use a different set of credentials/connection string for the database
If configured, use another connection string for verbose logging
Enable the Vidyano.ForceHttps app setting to enable HSTS
Configure TLS 1.2 to be the minimum TLS version
Disable the admin user and use another named user that is an administrator or make sure that the password is strong (and different from development)
Automation protection
If the web app is available on the public internet and can be accessed without logging in (e.g. contact form) you should provide extra protection against abuse. This can easily be done by using the Google reCaptcha library to validate the request.