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.
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
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.
In .NET Core, you will want to take advantage of the secrets manager. You can find more information here:
In Visual Studio 2019, you can access these via right-click on your project and select Manage User Secrets.
In Visual Studio Code, you can install the following extension to get the same behavior:
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
Icons
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 Iconify, 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.
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
}
}
}
}
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.
Migration scripts for v5 Repository database
Make sure you have a backup before running the scripts
-- 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'
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
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.
Verbose Logs
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.
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.
// 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());
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, ...)
Azure AD SAML based Sign-on
Vidyano can be configured to use Azure AD as an authentication provider. In combination with the 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:
SourceGenerators
Vidyano makes use of the to offer various helpers.
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.
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)
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.
3.0
Coming soon
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.\
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
Index Generator
Model Generator
ProjectTargetType Generator
Generated Constant classes
All generated Constant classes are available under {RootNamespace}.Service.Generated namespace.
BusinessRuleNames
PersistentObjectTypes
PersistentObjectAttributeNames
ProgramUnitNames
ProgramUnitItemsNames
QueryNames
QuerySources
ActionNames
Languages
MessageKeys and Messages
AppRoles
WebsiteNames
Obsolete.PersistentObjectTypes
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 Index class.
A V{Entities} property on the Context if it does not already exist.
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.
Only the IId interface will be copied to the QueryType.
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.
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.
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.
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
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.
Service
v6 release notes
Instead of actual release notes per version we maintain a list of various new features we introduced over the years
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;}
}
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.
The https://haveibeenpwned.com/Passwords 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)
Expiry date and time
IP address
Optionally the original user when an user is impersonated
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).\
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.
AsyncStreamingAction
Added AsyncStreamingAction for handling streaming responses
Added StreamingDialogOptions for customization
Added AuthenticatedRequest support on AsyncStreamingAction
Improved dialog options with default properties
.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
Fixed IgnoreProperty for Entity Framework Core
Improved disposal of ActionHandlers
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
Added NullUpdatableLog implementation
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
Temporarily disabled TypeForwardedTo for obfuscator support
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
Fixed handling of null RemoteIpAddress in GetClientIpAddress
Maintenance
Prefer literal contains for better performance
Help developer when reference points to value object
Improved fullTypeName handling
Let Poll also check that cache is loaded
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
Keep SQL CacheUpdates backwards compatible
Updated packages
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
Updated packages
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
TODOs and code cleanup
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
Small tweaks and TODOs
Updated packages
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
Fixed issue with Api method not correctly logging exceptions
Fixed NRE inside SetValueFromObject
Fixed issue with Web3 not being detected from custom pages
Maintenance
Prefer file scoped namespaces throughout codebase
Use NuGet package icons
Better default handling of WhereEntity
Updated Web3
Updated packages
Bump copyright year
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
Make sure POA.Id stays in sync with name change
Skip custom queries for wrong entity type
Datadog sometimes failed when getting HttpRequest information
Maintenance
Show attribute visibility during synchronize (query vs read+new)
Set account before starting verbose log threads
Verify against UtcNow
Added signedPermissions on GetSharedAccessSignatureUrlForBlob
Note: Commits marked with (test) or [skip ci] have been excluded from this changelog as they are internal testing commits.
Security
Client
Web3 release notes
Previous
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);
}
Allow user registration
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);
}
}
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
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
Maintenance
Handle OnPreviewLoad in Manager.GetPersistentObject
Web: Improved handling of WindowsAuthentication
Add default ReadEdit/Vidyano.Import right for all users to allow RegisterImport
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
Maintenance
Expose Manager.TimeZone
Removed obsolete/outdated WPF related code
Ensure Vidyano is initialized/updated when using Api calls
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.
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.
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.
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 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)
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.
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 2021
December 2021
New Features
SCIM Enhancements
Added IScimHandler.OnPostUser hook
Better error info for invalid Operations in SCIM patch
Diagnostics
Added Advanced.OnDiagnostics hook
Added DiagnosticsArgs.AddAssembly helper
Fixes
Fixed Excel issue with empty rows
Fixed issue when users/administrators group name is changed
Convert empty string to null for BinaryFile?
Maintenance
Exposed whether PreviewLoadArgs was rerouted
Tweaked "could not sort on property" messages
Removed duplicate Base64UrlEncoded code
November 2021
New Features
ViewModels
Added ViewModels for automatic logic when working with views/view models
Added ReaderWriter lock when working with ViewModels naming rules
BinaryFile
Added BinaryFile type for file handling
BinaryFile enhancements with better conversion support
ObjectId
Added ObjectId type for unique identifiers
Value Objects
Added ValueObjects.SetPropertyName
Added ValueObjects.GetHandler helper
Allow value objects to use custom queries
User Management
Added IUser.IsMemberOfAny for group membership checking
Helper Methods
Added GetLookupValue extension method
Added Manager.IsWeb2OrGreater
Fixes
Fix for Open-XML-SDK issue #1070
Don't flag attribute as sensitive in new
Handle [KeyValueList] correctly for Database.ValueObjects query
Maintenance
Flag PersistentObjectAttribute.GetValue as obsolete
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.
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.
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.
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.
Changelog 2019
December 2019
New Features
Advanced Search Save/Load (#272, #274)
Complete advanced search save/load functionality
Persist search configurations
Fixes
Issue when loading Legacy Vidyano application
Fixed issue with ExportToExcel not respecting columns
Maintenance
Always include name in ProgramUnitItemGroup based on DefaultLanguage
Tweaks and improvements
November 2019
New Features
Persistent Object Enhancements
Added PO.KeepValueChanged
Keep track of value changes
Advanced Hooks
Added advanced hook to determine friendly filter
Better filter customization
Fixes
Fixed issue #273
Fixed issue with empty ProgramUnit staying
Don't throw when user agent is not found
October 2019
New Features
JWT Enhancements
Added JwtPayload support
Better JWT token handling
Query Ordering
Added option to explicitly order distinct values
Better control over query results
Repeating Jobs
Show extra info for repeating jobs (last execution, execution count)
Better job monitoring
Fixes
Fixed issue #270
Fixed issue when ContextProperty points to DbQuery
Fixed issue with Hasherid not working for EF POCO entity
Maintenance
Detect .NET 4.8
Pass targetContext correctly when filtering for load entity
September 2019
Fixes
Fixed NRE when cdncache.tmp is empty
August 2019
No commits in August 2019
July 2019
New Features
Service Actions
Added ServiceAction.GroupAction
ServiceActionActions improvements
Better action organization
Advanced Search
Expose Source.HasAdvancedSearch
Keep Source.HasAdvancedSearch for most operations on Source
Fixes
Fixed NRE in ExportToExcel
Fixed NRE in AdvancedSearch for obfuscated code
Fixed creating custom actions
Maintenance
Added extra understood Type hints
Tweaked exception when FromServiceString fails
June 2019
Fixes
Fixed vulcanizer issue
Fixed PO.AddQuery when Queries.IsReadOnly
Fixed issue with PreClient on custom action
Maintenance
Ignore fuzz findings
May 2019
New Features
Query Enhancements
Moved persistent object id from QueryResultItem to QueryColumn
Better query structure
Fixes
Fixed AdvancedSearch not working on Actions class with other TContext
Fixed issue #261
Fixed issue #262
Maintenance
Warn for usage of Jurassic 3.0
April 2019
New Features
Azure Storage
Added extra AzureStorageConnector retry logic
Also retry again for SocketException in AzureStorageConnector
Use custom hook for ValidateAuthToken from Authorization header
DetermineMissingUserInRequest Basic Auth example
Testing
Added Tests query
Test: Memory stats
Test: Memory stats compiling
Test: Added ImpersonateViaHeader custom action
Fixes
Fixed issue #245
Fixed issue #244
Fixed issue #243
Fixed issue #130
Maintenance
Prefer ProfiledHttpClient
Partially allow HEAD on GetIndex
Return null when request is null for request.GetRequestUri()
January 2019
New Features
Excel Enhancements
Excel fix for Date(Time) that is changed during QueryExecuted
Better date handling in Excel exports
Helper Methods
Added StringEx.SmartJoin overload
More string utilities
Fixes
Fixed diagnostics issue when Bindings are empty
Fixed issue with cdncache and using http url as web2 version
Maintenance
Sample code updates
Prefer hc-sql server for sample code
ImageUrl initial implementation
Note: Commits marked with (test) have been excluded from this changelog as they are internal testing commits.
5.40.2+2a48896
Thursday, November 8th, 2018
Features
Added Advanced.IsSettingValueValid method to allow checking of value for custom settings
Changelog 2016
December 2016
New Features
5.45.0+26864bd
Monday, February 10th, 2020
Features
Added Advanced search save-load
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)
Changelog 2017
December 2017
New Features
Changelog 2018
December 2018
New Features
5.44.0+6e65421
Saturday, November 30th, 2019
Features
Added option to explicitly order distinct values
Changelog 2014
December 2014
New Features
Fixed issue with SetComputedAttribute not working when using proxy entities
GetLabel tweaks for better label handling
Fixed issue with Azure verbose logs not supporting viAudit syntax
Fixed issue with Web3 not triggering Manager.Initialize correctly
MultiString and IsEmail tweaks
ServiceLocator changes
Improved Web3 detection
Only filter on SortExpression if it has the same property type
RequestScopeProvider is a singleton
TypeCache lazy should use PublicationOnly instead of None
Scoped cache for SQL user store
Don't save security.json on startup when creating database users/groups
Updated packages
Shorten ImpersonateMessage message
Word added extra helpers
Tweaked NewUserArgs to use fixed Id for new user
PO Advanced expose Metadata
Updated packages
Optimize use cache
Prefer none lazy thread safety mode
Allow changed attribute names directly for UpdateCalculated
Ensure consistent ordering for website pages before save
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
Show logged url from feedback as notification (and hide screenshot if empty)
Make sure LogVerboseData PO uses whole width
Tweaked navigation behavior to only see as fromAction when a parent exists
Fixed retrying of initialization when failed on startup
Reduced time to 15 seconds (from 30)
Removed unneeded system message
Ensure cached HasGlobalSearch is updated
Default minimum IE version incremented to 10 (still supports 9)
Handle missing Vidyano connection string
Added missing parameter validations inside Manager public methods
Improved error messages when query's source is not found
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.
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)
Fixed issue with ExportToExcel on Advanced search not returning any rows
Fixed issue with verbose logging not working if repository cache failed to load
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
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)
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
Fixed issue that the current groups weren’t returned correctly for the current user
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
Fixed some issues when switching between Verbose modes
Fixed issue when report is accessed behind proxy (e.g., CloudFlare)
Maintenance
Added sync option for hidden attributes and detail queries
Changed default project web.config
Extended verbose logging
Updated EF to 5.2.0
Fixed EOL for POAReference file
Updated reports help documentation
Reports issues fixes
Constants for string array allocations
Fixed multi-threading issue with UpdateLastLoginDate
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
Fixed issue when throwing new ValidationException
Fixed patch importing
Maintenance
Made POA.GroupName setter public
Added DEV indication for exception
Added application start time
Extended GetReport xsd information
ACS dev messages
Handle Accept request header for reports
Prefer DbContext.SaveChanges for PersistChanges
Skip updating security.json when deleting user with rights
Added logging when report is accessed insecurely
Don't verbose log outgoing content for GetReport/Api
Insecure report tweaks
Added InstantSearchArgs.AddRepository
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
Fixed issue with Query UserRight not having filter
Fixed issue with newly created user not loading groups
Fixed issue with new user having Users groups twice
Fixed NRE when using inprocess http handler
Maintenance
Allow API/Instant request using default user
Excel changes
Added property order overrides for json serialization
Also order POAWR and POAAD
Keep original CanPopulateAttributeValues when calling PO.SaveDetails
Extra logging during cache update handling
Added default/cancel options for RetryAction
Update group cache item
Refresh rights queries when saving/deleting right
Changed GenerateLocalAuthToken to use same long expiration as staysignin
Changed TypeCache IsAnonymous lazy mode
Extra rights
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)
Fixed issue when trying to delete Log/Feedback
Fixed issue with anonymous projection on EF queryable
Fixed CodeFirst issue with new project
Fixed issue with newly created user not loading groups
Maintenance
Made email part of feedback async
Made request reading async/await
Added feedback hooks
Don't send Initial PO for default user
Don't allow viImpersonate on Group
Added LoginArgs for forward compatibility
Better detection for Code First mapped types
Fixed viImpersonate not working on PO
Request all known html files when a new version is requested
Extra logging for Web2Cdn + disable flag
Also use admin password for User user in new project
Made ImageUtils public
Handle ACS token validation through proxy
Don't show newoptions on ServiceAction' Rights query
Ignore RetryActionException when logging
Also show innerexception for UpdateException/DbUpdateException
Use same logic for decimal.ToServiceString() as client
Fixed issue with AutoCreateUsersInGroup on Security PO
New CDN appSetting
August 2017
New Features
Security Enhancements
Security architecture documentation
Security audit overview
Changed security screen to be more compact
Disable sliding auth token by default
Doubled auth token expiration days (and made configurable)
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
Fixed issue with ?id=X not working for api methods
Fixed issue when TranslatedString attribute doesn't return json but returns string
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
Fixed issue #77
Fixed issue #78
Fixed issue #79
Fixed issue #82
Fixed issue #83
Fixed issue #85
Fixed issue #86
Fixed issue with New Group still being added to patches
Fixed issue with distincts on asLookup query
Fixed issue with Random not being threadsafe
Maintenance
Consistent handling of TargetInvocationException
Log unhandled api errors
Added remark for Advanced.HandleForgotPassword
Added some extra information to exceptions
Allow loading of QueryFilters PO for Query
Throw error instead of set notification when ReOrder fails
More information for "Failed upgrading repository metadata."
Make sure we set new parent on detail attributes before checking rules
Added comment that POActions.Where is used for FindByObjectId
Don't show unselectable groups
Added xml comments to explain which claims are used for UnknownUser
Handle include filters when query is being added/removed during OnLoad
Use args for HandleSwaggerMetadata
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
Fixed issue with custom query with other TEntity not using DefaultPOA
Fixed issue when Native client connects to a production environment
Fixed NoDatabase issue with filters
Fixed invalid query sortoptions for query reports
Maintenance
Changed .Legacy target framework to 4.5
C# 7 refactor throughout
Don't initialize PO ActionCodes/HelpSet to empty collection
Added some reserved words for program unit names/routes handling
Don't send authtoken for default user for security reasons
Tweaked viRegenerateToken action
Show unmapped column that couldn't be sorted on
Moved legacy Web logic to separate assembly
Added AddSorted for ICollection
Calculate CultureOptions once
More boolean filter values
Fixed issue with web2 vulcanize resource only having read access
Disable viRegenerateToken when Token is read only
Fixed issue with Read right being required for OnPreviewAction
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
Fixed issue with settings during NoDatabase synchronize
Maintenance
Added Advanced.Poll hook
Only check Web2Version setting if ManagerImplementation is Initialized
Removed tag for new web components
Also show overridden settings in custom settings query
Changed new website template to use https for google fonts
Added ConfigureAwaitChecker Analyzer
Resharper: Allow vi prefix in methods
Added instant search docs
Added override vidyano settings docs
Don't check for new repository version when using NoDatabase
Show correct exception when NoDatabase RepositorySynchronizer fails
Show websites web2 version in diagnostics
Added ValueTuple package in Test project
Added more EditorBrowsable hints
Enabled C# 7 for ReSharper
Refactor: Split Query related POActions methods in partial file
Refactor SaveNew/SaveExisting
Reduced Web2Cdn versionLock
Made refactored methods protected for SaveNew/SaveExisting methods
Added ReferencePOActions example
Renamed POActionsReference
Include POActionsReference in NuGet package
Use C# 7 Roslyn compiler for building NuGet package
Tweaked POActionsReference
Ensure that VidyanoDbCache always has all the system settings
Refactor for C# 6/7 language features
Hide Query.GroupedBy
Fixed #10
Updated Add POActions wizard
Fixed issue when POActionsReference is used on new project
Changed exception for OnAddReference/OnRemoveReference without parent
Don't try to add missing ignored system settings for NoDatabase
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
Fixed issue with translations query not working after adding new lang
Fixed issue with invalid csv being generated
Maintenance
Made IOffset public
Added release notes
Tweaked default .tsconfig
Fixed builder issues with new semantic versioning
Updated release notes style
Added glossary
Removed QueryResultItem.Breadcrumb
Changed CORS handler to allow origin *
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
Fixed issue with new DataType not saving correctly
Fixed issue with POAWR on old ui
Fixed issue with new language being kept on error
Fixed issue with bulk edit on POA
Fixed issues when editing user rights
Maintenance
Changed TargetFramework to 4.5.2 (then back to 4.5)
Use NuGet for DocumentFormat.OpenXml (#19)
Missing translations
Fixed xml documentation on CreateTransactionScopeForAction
Updated usage for Effort
Don't fail on AddUserToGroup if user is already in that group
WIP for #22
Hide old type hints for Web2 client
Use base interface to discover DbSet/ObjectSet
Removed unneeded converting to and from base64 #25
Fixed issue with invalid version being used for comparison
Show better exception when enumerable can't be sorted
Performance tweak when filtering reference attribute
Not so private
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.
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
Updated DocumentFormat.OpenXml (reverted to 2.7.2 for compatibility)
Updated Newtonsoft.Json to 12.0.1
Updated NuGet packages
Builder changes
November 2018
New Features
Performance Optimizations
Optimized POA constructor
Optimized BulkConstructPersistentObjectAsync
Optimized IncludeFilters logic
Optimized IsAllowed checking
Performance improvements throughout
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
Fixed NRE when Sorting on reference property with invalid DisplayAttribute
Fixed issue when saving new DataType
Maintenance
Added ITargetContext interface
Profile precision changed to 0.01ms
Made PO.GetDisplayAttributeValue synchronous
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
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
Handle empty ObjectId for viAudit
Allow adding of viAudit UserRight
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
Persist changed attributes after unchanged
Maintenance
Set Import PO as OpenInEdit
Profile CreateUserSession creation
Replace LogVerboseData's authToken with expiration info
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
Maintenance
Return AuthToken as header when received as header
WebException can have null Response
Fixed issue in .NET example in reports doc
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
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
Added PO.IsBreadcrumbSensitive
Flag application as having sensitive data
Also flag UserHostAddress and RequestId as sensitive
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
Made POA.ToolTip settable
Fixes
Fixed issue when deleting attributes that would remove unrelated columns
Fixed issue with Feedback misusing IsReadOnly
Reset attributes when SaveDetails fails
Fixed POAWRBuilder not saving
Fixed issue #152
Fixed issue with OnNew flagging PO as IsBreadcrumbSensitive
Fixed ArgumentNullException when saving User without filling in username
Maintenance
Missing translations
ServicePointManager changes for Web2Cdn
Keep PO.IsReadOnly logic when New/BulkEdit/Delete is called directly
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
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.
Added detection of .NET 4.8 in diagnostics page
Added JwtPayload class
Added advanced hook to determine friendly filter
Added PersistentObject.KeepValueChanged
Added advanced hook for customizing Advanced search
Added advanced hook when a user opens its User settings page
Changes
Tweaked exception when FromServiceString fails
Show extra information for repeating jobs (last execution, execution count)
Don't remove request data when disposing UserSession
Fixes
Don't throw when user agent is not found
Fixed issue when creating custom actions from Management
Fixed NullReferenceException when cdncache.tmp is empty
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
Unit Testing
Added Vidyano unit tests
Renamed Service to Client for better clarity
Translation Export/Import
Added Export/Import functionality for translations
Allows easier localization management
Uses DataExport icon
Fixes
Fixed issue with StackedAreaChart
Fixed issue with BinaryFile on OpenAsDialog
Ignore NullReferenceException on System.Web's AssociateWithCurrentThread
Maintenance
Made OnImport methods public
Allow OK/Notice/Warning notifications on OpenAsDialog Save (shows on query)
Allow RegisterStream with null as key
November 2014
New Features
Dynamics System
Full dynamic schema implementation released
Show in management (Advanced -> Dynamics)
Allow New/Delete from management
Show Collections/Security queries on DynamicSchema
Allow configuring of Security on DynamicSchema
Added default PersistentObject actions class for Dynamics (DefaultPersistentObjectActions`1)
Diagnostics
Added comprehensive diagnostics functionality
Better insight into system behavior
OpenAsDialog State
Added StateBehavior OpenAsDialog
Web: Added PersistentObject.openAsDialog support
Better dialog management
Fixes
Fixed issue with OpenAsDialog and ComboBox
Fixed issue with optimize select
Fixed issues with Session setting
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
Maintenance
Changed Export to Excel to ignore trimming on text columns
Include max users information on License PO
Performance fix when saving UserSettings
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]
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
Maintenance
Updated hashing to bcrypt(10)
Added parseJSON function
Added Sort hook
Copied Jurassic xml documentation
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
January 2014
New Features
Query Enhancements
Added charts on Query
Added inherited rights on users/groups
Added optional Query argument for Find/GetEntity
Fixes
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
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
Maintenance
Updated to WebApi 2.1 (5.1)
Added groupname on persistent object attribute clone
Auto-apply text search filter based on propertyType
Changed New behavior to hide attributes that don't have New right
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.
Convert Language to ILookupKeyValueData
Reliable async messaging
Major performance improvement for bulk operations
Show tooltip for locked settings
Missing dialog translations
Prefer User Name instead of DisplayName in logs
Fixed bulk construct on POA/PUI/Settings using disposed actions
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.
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 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,
}
// E.g. select all detailLines from lines
[].concat(...this.lines.map(d => d.detailLines))
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 Manager.LogEntry to get client version, user agent and requestId
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
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
5.35.5+2316022
Friday, March 30th, 2018
Features
Vidyano will now throw a SaveFailedException inside SaveExisting/SaveNew/SaveDetails when it has an error
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
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)
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)
Fixed issue with authenticate not updating internal caches first
Fixed issue when double-saving new feedback (following saves are skipped when ObjectId is not empty)
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.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
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
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/…)
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.30.0+530afaf
Sunday, December 28th, 2017
Features
Added Advanced.StorageProvider to handle reading/writing of verbose log content ()
5.27.0+6b9495e
Friday, October 27th, 2017
Features
Added Advanced.TryReadDataFile/WriteDataFile hook to customize loading json files from App_Data
5.33.1+12ad63a
Thursday, February 22nd, 2018
Features
Added support for Pwned Password list (https://haveibeenpwned.com/Passwords) to automatically block breached passwords
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 ()
5.26.2+bccf416
Wednesday, October 11th, 2017
Features
Added ability to define default/cancel button index for RetryAction
5.28.2+bc49431
Thursday, November 30th, 2017
Features
Added Advanced ACS hook to passthrough a custom domain
5.19.0+0964f9
Wednesday, May 24th, 2017
Features
Added ability to request PO on backend using IsNew directly
5.25.3+8224b3b
Tuesday, September 19th, 2017
Features
Added extra per PO unique salt for securing the SecurityToken
Changed ToServiceString for enums to use default ToString (allows undefined enum values to be converted to numeric value)
Fixes
Fixed issue with Verbose logs filtering
5.16.0+aae2a8
Friday, April 21st, 2017
Changes
Improved performance when searching verbose logs on Created on
Handle searching on User/NullableUser attributes
Marked ConvertFromCommonMark as obsolete
Allow sorting of attribute with unsortable data type when using sort expression
Fixes
Fixed DbSort clause issue when sorting on reference attribute that isn’t visible
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.13.1+c8fdb1
Wednesday, March 22nd, 2017
Features
Added per website setting for Web2 version
Fixes
Fixed issue with NoDatabase mode not synchronizing repository changes
5.17.0+aaa255
Thursday, April 27th, 2017
Features
Added ability to search for last X days on date(time) attributes (using Last 2 days would return all records for today and yesterday)
Added action on reports to regenerate the token to a new random secure token
Added ability to return distinct values in descending order (by setting the args.Ascending to false in the GetDistinctValues method)
Added action to restart the Web App on the Client -> Websites query in the Management part
Changes
Added extra features to AzureStorageConnector (working with Content-Type, Content-Encoding and generating Shared Access Signature)
For pure Web2 applications it is now possible to remove the Templates array inside the model.json
Removed developer only actions from Management part from model.json (eg Synchronize, RefreshFromTranslations, StartStop, …) to reduce merge conflicts
Fixes
Fixed issue when deploying a new website to Azure that the bindings would be lost
5.21.1+923828
Tuesday, July 18th, 2017
Features
Added ability to disable computing of total items for queries, e.g. skipping the extra count call to the database
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
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
5.24.0+a20f7c
Thursday, August 31th, 2017
Features
Added the PreviewLoadArgs.HandleAsNew method to convert a load to a new
Made the auth token expiration time in days configurable (app settings Vidyano.AuthTokenExpiration and Vidyano.AuthTokenExpirationStaySignedIn)
Changes
Never use Web2 CDN if Vidyano.Web2 NuGet package is installed
Made PersistentObjectAttributeWithReference.SelectInPlace property public
Always detect classes with ComplexTypeAttribute as being mapped to the database
Fixes
Fixed issue with ?id=X not working for api methods
Fixed issue with distinct values for translated string attributes
Fixed issue with DefaultPersistentObjectActions being used for internal Vidyano objects
5.22.1+557c11
Friday, July 28th, 2017
Features
Added ability to skip data security when using GetEntity/FindByObjectId
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
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
5.11.1+d7647c
Tuesday, March 14th, 2017
Features
Added ApiMethodAttribute.NeedsAuthentication to require Authorization header
Added ability to manage filters for users using code
Added Advanced.Poll method to add extra logic to /poll request
Added ability to override Vidyano Settings using AppSettings ()
Changes
Don’t serve index html for static resources that are not found
Use all application languages for date operations (today, …)
Improved performance when saving model changes in Verbose mode
Fixes
Fixed issue with empty language value not being set when it has the same translated value as English
Fixed issue with some translations being incorrectly reused
5.7.1+554316
Wednesday, February 1st, 2017
Features
Added ExportToCsv action
5.1.60401.4035
Friday, November 25th, 2016
Features
Allow new ProgramUnit in Advanced.OnBuildProgramUnits
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
For security reasons we no longer send or require an auth token for the default user of an application
Show the property name when we couldn’t sort on an unmapped property
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
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
Changed the Security page to be more compact using a single Authentication Providers attribute
Disabled sliding expiration on auth tokens by default, old behavior can be enabled using the Vidyano.SlidingAuthToken app setting
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
Fixed issue with circular group memberships
Added Manager.GetUsersForGroup method
Use DocumentFormat.OpenXml NuGet 2.7.1
Changes
Updated CommonMark.NET NuGet dependency to 0.15.0
Updated WindowsAzure.Storage NuGet dependency to 8.0.1
Show better exception when sorting fails on custom IEnumerable query
Removed DB call when filtering on reference attribute
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
Show validation errors from hidden attributes in PO Notification
Added Vidyano.TransactionIsolationLevel app setting to determine IsolationLevel
Added POActions.OnBulkSave
Added IUser.ChangeName
Changes
Updated CommonMark.NET NuGet dependency to 0.14.0
Updated Microsoft.Data.* NuGet dependencies to 5.8.1
Updated WindowsAzure.Storage NuGet dependency to 7.2.1
Tweaked new website template to use https:// for google fonts url
Tweaked new webcomponent template to remove obsolete content tag
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).
Security
Note: This documentation has been updated for v6. Please refer to the v6 Security documentation for the latest information.
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.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
5.8.1+67bcab
Monday, February 13th, 2017
Changes
Changed cors handler to use * for allowed origin
Fixes
Fixed issue with exception in custom Web class constructor not being logged correctly
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!
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.\
Installation (Legacy)
Installation and software requirements
For Vidyano v6 check Getting started, you no longer need the extension as everything is managed with NuGet packages
In order to get started you will need to have the following software installed:
You will also need to have the Vidyano Extension installed from the Visual Studio Gallery:
for Visual Studio
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
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.
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
Changing the Delete label on a Persistent object that has soft-delete enabled.
Another use case for changing the Save label is when a virtual persistent object is shown for a custom action.
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
Fixed issue when using bulk-edit on Users
Fixed issue when using bulk-edit on UserRights
Fixed issue when using bulk-edit on PersistentObjects
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);
}
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
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;
}
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);
}
}
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");
}
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
Users
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.
Overridden settings will be shown as read-only in the Management part.
Best Practices
Note: This documentation has been updated for v6. Please refer to the v6 Security - Best Practices 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)
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.
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.”