Veracity.Core.Api.V4 1.0.20260320.8

Prefix Reserved
dotnet add package Veracity.Core.Api.V4 --version 1.0.20260320.8
                    
NuGet\Install-Package Veracity.Core.Api.V4 -Version 1.0.20260320.8
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Veracity.Core.Api.V4" Version="1.0.20260320.8" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Veracity.Core.Api.V4" Version="1.0.20260320.8" />
                    
Directory.Packages.props
<PackageReference Include="Veracity.Core.Api.V4" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Veracity.Core.Api.V4 --version 1.0.20260320.8
                    
#r "nuget: Veracity.Core.Api.V4, 1.0.20260320.8"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Veracity.Core.Api.V4@1.0.20260320.8
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Veracity.Core.Api.V4&version=1.0.20260320.8
                    
Install as a Cake Addin
#tool nuget:?package=Veracity.Core.Api.V4&version=1.0.20260320.8
                    
Install as a Cake Tool

Veracity.Core.Api.V4 Documentation

Welcome to the Veracity Platform Graph API SDK for .NET! This comprehensive package enables seamless integration with Veracity's identity and resource management system.



What's New in V4

  • ? Tenant-centric architecture - All operations organized by tenant
  • ?? Fine-grained permissions - Element-level access control
  • ?? Element management - Hierarchical resource structures
  • ?? Type-safe responses - Strongly-typed extension properties
  • ?? Enhanced authorization - Built-in attribute-based protection
  • ?? Multi-framework - .NET 6, 7, 8, and 9 support

Installation

dotnet add package Veracity.Core.Api.V4

Quick Setup

1. Configure appsettings.json

{
  "Veracity": {
    "veracityGraphBaseUrl": "https://api.veracity.com/apiv4/v1",
    "applicationPrefix": "myapp",
  "serviceId": "your-application-id-from-developer",
    "clientId": "your-client-id",
    "clientSecret": "your-client-secret",
    "subscriptionKey": "your-subscription-key",
    "azureAdB2C": {
      "instance": "https://login.microsoftonline.com/tfp/",
      "domain": "dnvglb2cprod.onmicrosoft.com",
      "policy": "B2C_1A_SignInWithADFSIdp",
      "clientId": "your-client-id",
      "callbackPath": "/signin-oidc",
      "scopes": "https://dnvglb2cprod.onmicrosoft.com/83054ebf-1d7b-43f5-82ad-b2bde84d7b75/user_impersonation"
    }
  }
}

2. Configure Services (Startup.cs)

public void ConfigureServices(IServiceCollection services)
{
    // Add Veracity authentication
    services.AddVeracity(Configuration);
    
    // Add Veracity Graph API
    services.AddVeracityGraphApi<DotNetLogger>();
    
    // Configure authentication
  services.AddAuthentication(options =>
        {
   options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
 })
    .AddVeracityAuthentication(Configuration)
        .AddCookie();
    
    services.AddControllersWithViews();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseAuthentication();
    app.UseVeracity();
    app.UseAuthorization();
    
    // Optional: Add profile picture middleware
    app.UseVeracityProfilePicture();
  
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
      name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

3. Use in Your Code

public class MyController : Controller
{
    private readonly IVeracityGraphClient _veracityClient;

    public MyController(IVeracityGraphClient veracityClient)
{
        _veracityClient = veracityClient;
    }

    [VeracityAuthorization]
    [HttpGet("api/tenants/{tenant_id}/users")]
    public async Task<IActionResult> ListUsers(string tenant_id)
    {
   var users = await _veracityClient.Users.FindUsers(
            tenant_id, 
   top: 25, 
        skip: 0);
     return Ok(users);
    }

    [VeracityAuthorization("admin", "editor")]
    [HttpPost("api/tenants/{tenant_id}/licenses")]
    public async Task<IActionResult> AddLicense(
        string tenant_id, 
        [FromBody] Guid userId)
    {
        var license = await _veracityClient.ThisApplication.AddLicense(
   tenant_id,
         new LicenseRequest
    {
 EntityId = userId,
                LicenseType = EntityTypes.profile,
                AccessLevel = "editor"
            });
   return Ok(license);
    }
}

Key Features

Tenant Management

// Get tenant information
var tenant = await _veracityClient.Tenants.GetTenant(tenantId);

// List all tenants for your application
var tenants = await _veracityClient.Tenants.GetTenants(applicationId);

// Update tenant properties
var patch = tenant.MakeJsonPatch()
    .AddOrUpdateProperty("customField", "value");
await patch.ExecutePatchTenantAsync();

User Management

// Find user by email
var user = await _veracityClient.Users.GetUserByEmail(tenantId, "user@example.com");

// List users with fluent query builder (recommended)
var users = await _veracityClient.Users.Query(tenantId)
    .Filter(u => u.Name == "John Doe")
    .Or(u => u.Name == "Jane Doe")
    .And(u => u.IsLocked == false)
    .Search("engineer")
    .Top(25)
    .ExecuteAsync();

// Get user's groups and applications
var groups = await _veracityClient.Users.GetGroupsForUser(tenantId, userId);
var apps = await _veracityClient.Users.GetApplicationsForUser(tenantId, userId);

Group Management

// List groups with query builder
var groups = await _veracityClient.Groups.Query(tenantId)
    .Filter(g => g.Name == "Administrators")
    .Or(g => g.Name == "Editors")
    .Top(25)
    .ExecuteAsync();

// Get group members (including nested)
var allMembers = await _veracityClient.Groups.GetMembersWithInheritedMemberships(
    tenantId, 
  groupId,
    new Dictionary<string, string>());

// Check if user is member
var isMember = await _veracityClient.Groups.IsUserMemberOfGroup(
    tenantId, 
    groupId, 
    userId);

Application & License Management

// Get application details
var app = await _veracityClient.ThisApplication.GetApplication(tenantId);

// Verify user has license
var license = await _veracityClient.ThisApplication.VerifyUserLicense(
  tenantId, 
    userId);

// Get all users with licenses (including inherited from groups)
var users = await _veracityClient.ThisApplication.GetUsersWithInheritedAccess(
    tenantId);

// Add license to user
var newLicense = await _veracityClient.ThisApplication.AddLicense(
    tenantId,
new LicenseRequest
    {
        EntityId = userId,
        LicenseType = EntityTypes.profile,
AccessLevel = "reader"
    });

Element Management (Application-Specific Resources)

// Create a root element (e.g., workspace, vessel, project)
var element = await _veracityClient.ThisApplicationElements.CreateElement(
    tenantId,
    new ElementRequest
    {
   Name = "My Workspace",
        ElementExternalId = "ws-001",
        ElementType = "Workspace",
        Description = "Main project workspace",
        ElementTypeIconUrl = new Uri("https://cdn.example.com/icon.png")
    });

// Create child element
var child = await element.AddChildElement(new ElementRequest
{
    Name = "Sub-workspace",
    ElementExternalId = "ws-001-sub",
    ElementType = "Workspace"
});

// Grant user access to element
await element.AddRights(new ElementRightRequest
{
    EntityId = userId,
    LicenseType = EntityTypes.profile,
    AccessLevel = "editor"
});

// Get all elements user has access to
var userElements = await _veracityClient.ThisApplicationElements
    .GetUserElements(tenantId, userId);

Custom Typed Responses

Create strongly-typed models for your extension properties:

// Define your typed model
public class MyTenant : TypedTenantBase
{
    public List<string> VesselList
    {
        get => GetValue<List<string>>();
    set => SetValue(value);
    }
    
    public string Department
    {
        get => GetValue<string>();
      set => SetValue(value);
    }
    
    // Access properties from other applications
    public List<string> ManagementCompanies => 
  GetExternalValue<List<string>>("vtmd2");
}

// Convert response to typed version
var typedTenant = await _veracityClient.Tenants
    .GetTenant(tenantId)
    .ToTyped<MyTenant>();

Console.WriteLine($"Department: {typedTenant.Department}");
Console.WriteLine($"Vessels: {string.Join(", ", typedTenant.VesselList)}");

Supported Base Types:

  • TypedTenantBase
  • TypedUserBase
  • TypedGroupBase
  • TypedApplicationBase
  • TypedLicenseBase
  • TypedMemberBase
  • TypedElementBase

Authorization Attribute

Protect your endpoints with built-in license verification:

// Basic authorization - verify user has valid license
[VeracityAuthorization]
public async Task<IActionResult> MyAction(string tenant_id)
{
    // User has a valid license
}

// Require specific access levels
[VeracityAuthorization("admin", "editor")]
public async Task<IActionResult> AdminAction(string tenant_id)
{
    // User has admin OR editor access level
}

// Configure tenant ID location
[VeracityAuthorization(
    TenantIdIn = IdCarrierTypes.Path,
    TenantIdKey = "tenant_id",
    CacheWindowSizeInMinutes = 5)]
[HttpGet("api/tenants/{tenant_id}/data")]
public async Task<IActionResult> GetData(string tenant_id)
{
    // Tenant ID extracted from path parameter
}

// Element-level authorization
[VeracityAuthorization(
    ElementIdIn = IdCarrierTypes.Path,
    ElementIdKey = "elementId",
    AccessLevels = new[] { "editor", "owner" })]
[HttpPost("api/elements/{elementId}/data")]
public async Task<IActionResult> UpdateElement(string elementId)
{
 // User has editor or owner rights on the element
}

Profile Picture Middleware

Display user profile pictures in your web application:

// Configure in Startup.cs
app.UseVeracityProfilePicture(
    generateInitialsAvatar: true,
  background: Color.DarkBlue,
    text: Color.White);

// Use in Razor views
<img src="@user.ProfilePictureUrl" alt="@user.Name" />

// Or get programmatically
var imageBytes = await user.GetProfileImage();

If a user doesn't have a profile picture, the middleware automatically generates an initials-based avatar.


OData Queries

Use the fluent query builder for type-safe, readable queries:

// Simple filter
var users = await _veracityClient.Users.Query(tenantId)
    .Filter(u => u.Name == "John Doe")
    .Top(25)
    .ExecuteAsync();

// Complex filter with OR and AND combinations
var users = await _veracityClient.Users.Query(tenantId)
    .Filter("tenantId eq 'abc'")              // Initiates filter
    .And(u => u.Name == "John")               // Commits previous, starts new AND group
    .Or(u => u.Name == "Jane")                // Adds OR to current group
    .Or(u => u.Name == "Bob")                 // Adds OR to current group
    .And(u => u.IsLocked == false)            // Commits OR group, adds new AND clause
    .Top(50)
    .OrderBy(u => u.Name)
    .ExecuteAsync();
// Produces: tenantId eq 'abc' and (name eq 'John' or name eq 'Jane' or name eq 'Bob') and isLocked eq false

// Search with filters
var users = await _veracityClient.Users.Query(tenantId)
    .Search("engineer")
    .Filter(u => u.IsLocked == false)
    .Top(25)
    .Skip(0)
    .OrderByDescending(u => u.Name)
    .Select(u => u.Name)
    .Select(u => u.Email)
    .ExecuteAsync();

// Pagination support
if (users.NextPageUrl != null)
{
    var nextPage = await users.GetNextPage();
}

Query Builder Pattern:

  • Filter() - Initiates the filter (only use once at the start)
  • And() - Commits current group and starts a new AND clause
  • Or() - Adds an OR condition to the current group
  • Top(), Skip() - Pagination
  • OrderBy(), OrderByDescending() - Sorting
  • Search() - Free-text search
  • Select() - Field projection

Raw OData Queries

For advanced scenarios, you can use raw OData queries:

var query = new OdataRequest
{
    Filter = "name eq 'John Doe' and email ne 'test@example.com'",
    Search = "engineer",
    OrderBy = new[] 
    { 
        new OrderingElement { Field = "name", Type = OrderTypes.Ascending }
    },
    Top = 25,
    Skip = 0,
    Select = new[] { "name", "email", "userId" }
};

var users = await _veracityClient.Users.ListUsers(tenantId, query);

Supported OData Operators:

  • Comparison: eq, ne, gt, lt, ge, le
  • Logical: and, or, not
  • String: ("search.ismatch('hn', 'name'),("search.ismatch('hn', 'name'), ("search.ismatch('hn', 'name'), ("search.ismatch('hn', 'name')

Extension Properties

Manage custom metadata on any entity:

// Add or update properties
var patch = user.MakeJsonPatch()
    .AddOrUpdateProperty("customField", "value")
    .AddOrUpdateProperty("tags", new List<string> { "tag1", "tag2" });
await patch.ExecutePatchUserAsync();

// Remove property
var patch = user.MakeJsonPatch()
 .RemoveProperty("customField");
await patch.ExecutePatchUserAsync();

// Read property
var value = user.GetPropertyValue<string>("customField");

// Read property from another application
var externalValue = user.GetPropertyValue<string>("otherapp", "propertyName");

Properties are automatically prefixed with your application prefix (configured in appsettings.json).


Authentication Modes

Authorization Code Flow (Web Applications)

Default mode for interactive user applications:

services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
     options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddVeracityAuthentication(Configuration)
    .AddCookie();

Client Credentials Flow (Daemon Applications)

For service-to-service communication:

services.AddVeracityClientCredentialsAuthentication(
    clientId: "your-client-id",
    clientSecret: secureClientSecret);

Note: Update the scope in configuration to:

{
  "Veracity": {
    "azureAdB2C": {
      "scopes": "https://dnvglb2cprod.onmicrosoft.com/83054ebf-1d7b-43f5-82ad-b2bde84d7b75/.default"
    }
  }
}

Error Handling

All API operations throw ServerException with detailed error information:

try
{
    var user = await _veracityClient.Users.GetUserByEmail(tenantId, email);
}
catch (ServerException ex)
{
    var error = ex.GetErrorData<ErrorDetail>();
    
    Console.WriteLine($"Error: {error.Message}");
    Console.WriteLine($"Correlation ID: {error.CorrelationId}");
    Console.WriteLine($"Support Code: {error.SupportCode}");
    Console.WriteLine($"HTTP Status: {ex.Status}");
    
    // Log for support
    _logger.LogError(ex, 
        "API error - Correlation ID: {CorrelationId}", 
        error.CorrelationId);
}

Common Status Codes:

  • 200 OK - Success
  • 400 Bad Request - Invalid parameters
  • 401 Unauthorized - Authentication failure
  • 403 Forbidden - Insufficient permissions
  • 404 Not Found - Resource doesn't exist
  • 409 Conflict - Resource conflict
  • 500 Internal Server Error - Server error

API Interfaces

Main Interfaces

  • IVeracityGraphClient - Main entry point
    • Tenants - Tenant operations
    • Users - User operations
    • Groups - Group operations
    • Applications - Application and license operations
    • Elements - Element operations
    • Me - Current user operations
    • ThisApplication - Quick access to your configured application
    • ThisApplicationElements - Quick access to your application's elements

Key Operations by Interface

ITenantsApi

  • GetTenant, GetTenants, PatchTenant
  • GetAdmin, GetAdmins
  • GetUsersAndGroups

IUsersApi

  • GetUserByEmail, GetUser, GetUserInTenant
  • ListUsers, ResolveUsers
  • GetGroupsForUser, GetApplicationsForUser, GetTenantsForUser
  • PatchUser

IGroupsApi

  • GetGroups, GetGroup
  • GetGroupMembers, GetMembersWithInheritedMemberships
  • IsUserMemberOfGroup, GetMemberOf
  • GetApplications, PatchGroup, PatchMember

IApplicationsApi

  • GetApplications, GetApplication
  • GetLicenses, VerifyUserLicense, GetUsersWithInheritedAccess
  • AddLicense, SetAccessLevel, UpdateLicense, DeleteLicense
  • GetAdministrators, PatchApplication

IElementsApi

  • ListElements, ListChildElements, GetElementTree
  • GetElement, CreateElement, CreateChildElement
  • PatchElement, DeleteElement
  • GetElementRights, AddElementRights, UpdateElementRights, DeleteElementRights
  • GetUserElements, GetUserElement

IMe

  • GetMyInfo, GetMyApplications, GetMyTenantApplications
  • GetMyGroups, GetMyTenants, GetMyTenantsWithApplication
  • VerifyUserPolicy

Migration from V3 API

If you're migrating from the V3 API:

Configuration Changes

V3:

services.AddVeracityServices(myApiV3Url);

V4:

services.AddVeracityGraphApi(veracityGraphBaseUrl);

API Changes

V4 uses a tenant-centric approach. All operations now require a tenant context:

V3:

var services = await _my.Services(new UserAndServiceQuery { userId });

V4:

var apps = await _veracityClient.Users.GetApplicationsForUser(tenantId, userId);

Profile Picture

V3: Manual implementation required

V4: Built-in middleware

app.UseVeracityProfilePicture();

Console Application Example

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Veracity.Core.Api.V4;

var configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .Build();

var clientSecret = new SecureString();
foreach (var c in Environment.GetEnvironmentVariable("CLIENT_SECRET"))
{
    clientSecret.AppendChar(c);
}

var services = new ServiceCollection()
    .AddVeracity(configuration)
    .AddVeracityClientCredentialsAuthentication(
   "your-client-id",
 clientSecret)
    .AddVeracityGraphApi()
    .BuildServiceProvider();

using var scope = services.CreateScope();
var client = scope.ServiceProvider.GetRequiredService<IVeracityGraphClient>();

// Use the client
var users = await client.Users.ListUsers(
    "tenant-id", 
 new Dictionary<string, string>());
    
Console.WriteLine($"Found {users.Items.Length} users");

Best Practices

  1. Use Distributed Caching - Configure Redis or memory cache for better performance
  2. Implement Custom Logging - Extend LogAdapter for your logging infrastructure
  3. Handle Pagination - Use GetNextPage() for large result sets
  4. Use Batch Operations - Prefer ResolveUsers() over loops
  5. Proper Extension Property Naming - Use MakePropertyName() for consistency
  6. Error Handling - Always catch ServerException and log correlation IDs
  7. Access Level Validation - Check if application supports access levels before setting them
  8. Don't Dispose Manually - Let IoC container manage IVeracityGraphClient lifetime

Support and Resources

Documentation

Getting Help

  • Technical Issues: Contact Veracity Support with the Correlation ID from error responses
  • Integration Questions: Consult the developer portal
  • Feature Requests: Contact your Veracity representative

Sample Code

  • Review the WebApplicationNet7 project for ASP.NET Core examples
  • Check CCTestApp for console application patterns
  • See WebApplicationNet7/Controllers/TestApi.cs for API usage examples

Version History

v4.2.0 (Current)

  • Client credentials flow support
  • Multi-framework targeting (.NET 6, 7, 8, 9)
  • Enhanced element hierarchy management
  • Improved error handling and logging

v4.1.0

  • Custom typed response support
  • Enhanced OData query support
  • Profile picture middleware
  • Improved caching strategies

v4.0.0

  • Initial V4 release
  • Tenant-centric architecture
  • Element management
  • Enhanced access control
  • Server-sent events

License

This SDK is provided by DNV and is subject to the terms and conditions of your Veracity Platform agreement.


Ready to get started? Check out the Comprehensive Guide for detailed documentation and examples!

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Veracity.Core.Api.V4:

Package Downloads
Veracity.Core.Api.V4.Privileged

SDK for accessing Veracity Tenant Management Privileged API.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.20260320.8 104 3/20/2026
1.0.20251203.3 728 12/3/2025
1.0.20251202.10 700 12/2/2025
1.0.20251202.9 709 12/2/2025
1.0.20241120.7 265 11/20/2024