Veracity.Core.Api.V4 1.0.20251203.3

Prefix Reserved
dotnet add package Veracity.Core.Api.V4 --version 1.0.20251203.3
                    
NuGet\Install-Package Veracity.Core.Api.V4 -Version 1.0.20251203.3
                    
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.20251203.3" />
                    
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.20251203.3" />
                    
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.20251203.3
                    
#r "nuget: Veracity.Core.Api.V4, 1.0.20251203.3"
                    
#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.20251203.3
                    
#: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.20251203.3
                    
Install as a Cake Addin
#tool nuget:?package=Veracity.Core.Api.V4&version=1.0.20251203.3
                    
Install as a Cake Tool

Veracity.Core.Api.V4 - Comprehensive Documentation

Table of Contents


Overview

The Veracity.Core.Api.V4 package is the official .NET SDK for the Veracity Platform Graph API. It provides comprehensive access to Veracity's identity and resource management system.

Key Features

  • Tenant Management - Organizational units for data isolation
  • User & Group Management - Identity and access control
  • Application Licensing - Service instance and license management
  • Element Management - Application-specific resource hierarchies
  • Fine-Grained Permissions - Element-level access control
  • Extension Properties - Custom metadata on all entities
  • Type-Safe Responses - Strongly-typed wrapper support
  • Built-in Authorization - ASP.NET Core attribute-based protection

Supported Frameworks

  • .NET 6
  • .NET 7
  • .NET 8
  • .NET 9

Installation and Setup

1. Install Package

dotnet add package Veracity.Core.Api.V4

2. Configuration (appsettings.json)

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

3. ASP.NET Core Setup (Startup.cs)

public void ConfigureServices(IServiceCollection services)
{
    // Load configuration
    services.AddVeracity(Configuration);
    
    // Add Veracity Graph API with logging
    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: Profile picture middleware
    app.UseVeracityProfilePicture();
    
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
    endpoints.MapControllerRoute(
name: "default",
  pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

4. Console Application Setup

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

var services = new ServiceCollection()
    .AddVeracity(configuration)
    .AddVeracityClientCredentialsAuthentication(clientId,clientSecret)
    .AddVeracityGraphApi()
    .BuildServiceProvider();

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

Quick Start Guide

Basic Usage

public class MyController : Controller
{
    private readonly IVeracityGraphClient _client;

    public MyController(IVeracityGraphClient client)
    {
        _client = client;
    }

    // Get tenant
    public async Task<IActionResult> GetTenant(string tenantId)
    {
     var tenant = await _client.Tenants.GetTenant(tenantId);
        return Ok(tenant);
    }

    // List users
    public async Task<IActionResult> ListUsers(string tenantId)
    {
     var users = await _client.Users.FindUsers(tenantId, top: 25);
        return Ok(users);
    }

    // Add license
    public async Task<IActionResult> AddLicense(string tenantId, Guid userId)
    {
  var license = await _client.ThisApplication.AddLicense(
   tenantId,
    new LicenseRequest
         {
    EntityId = userId,
    LicenseType = EntityTypes.profile,
          AccessLevel = "reader"
     });
        return Ok(license);
}
}

Core Concepts

Tenants

Tenants provide isolation boundaries for organizations.

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

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

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

Users

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

// List users with OData
var users = await _client.Users.ListUsers(tenantId, new OdataRequest
{
    Filter = "name eq 'John Doe'",
    Top = 25,
    Skip = 0
});

// Get user's groups
var groups = await _client.Users.GetGroupsForUser(tenantId, userId);

// Get user's applications
var apps = await _client.Users.GetApplicationsForUser(tenantId, userId);

Groups

// List groups
var groups = await _client.Groups.FindGroups(tenantId, top: 25);

// Get direct members
var members = await _client.Groups.GetGroupMembers(
    tenantId, 
    groupId, 
    EntityTypes.profile);

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

// Check membership
var isMember = await _client.Groups.IsUserMemberOfGroup(
    tenantId, 
    groupId, 
    userId);

Applications

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

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

// Get all users with licenses
var users = await _client.ThisApplication.GetUsersWithInheritedAccess(tenantId);

// Add license
var newLicense = await _client.ThisApplication.AddLicense(
    tenantId,
    new LicenseRequest
    {
        EntityId = userId,
        LicenseType = EntityTypes.profile
 });

Elements

// Create element
var element = await _client.ThisApplicationElements.CreateElement(
    tenantId,
    new ElementRequest
    {
     Name = "My Workspace",
        ElementExternalId = "ws-001",
        ElementType = "Workspace",
        Description = "Project workspace"
    });

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

// Add rights
await element.AddRights(new ElementRightRequest
{
    EntityId = userId,
    LicenseType = EntityTypes.profile,
    AccessLevel = "editor"
});

// Get user's elements
var userElements = await _client.ThisApplicationElements
    .GetUserElements(tenantId, userId);

API Reference

IVeracityGraphClient

Main entry point for all operations.

Properties:

  • Tenants - ITenants Api
  • Users - IUsersApi
  • Groups - IGroupsApi
  • Applications - IApplicationsApi
  • Elements - IElementsApi
  • Me - IMe
  • ThisApplication - IThisApplication
  • ThisApplicationElements - IThisApplicationElements
  • ApplicationId - Guid?
  • Prefix - string
  • Logger - LogAdapter

Methods:

string MakePropertyName(string name);
ExtensionProperty MakeExtensionProperty(string name, string value);
PropertyPatchDocument<T> MakeJsonPatch<T>(T obj, string name, string value);

ITenantsApi

Task<TenantResponse> GetTenant(string tenantId);
Task<ListEx<TenantResponse>> GetTenants(string applicationId);
Task<TenantResponse> PatchTenant(string tenantId, JsonPatchDocument<TenantResponse> body);
Task<UserRoles> GetAdmin(string tenantId, Guid userId);
Task<ListEx<UserRoles>> GetAdmins(string tenantId);

IUsersApi

Task<UserDetailsResponse> GetUserByEmail(string tenantId, string email);
Task<GlobalUserDetailsResponse> GetUser(Guid userId);
Task<PagedList<UserResponse>> ListUsers(string tenantId, Dictionary<string, string> odata);
Task<UserDetailsResponse> GetUserInTenant(string tenantId, Guid userId);
Task<GroupResponse[]> GetGroupsForUser(string tenantId, Guid userId);
Task<ListEx<ApplicationLicenseResponse>> GetApplicationsForUser(string tenantId, Guid userId);
Task<UserDetailsResponse> PatchUser(string tenantId, Guid userId, JsonPatchDocument<UserDetailsResponse> patchOps);

IGroupsApi

Task<PagedList<GroupResponse>> GetGroups(string tenantId, Dictionary<string, string> odata);
Task<GroupResponse> GetGroup(string tenantId, Guid groupId);
Task<ListEx<MemberResponse>> GetGroupMembers(string tenantId, Guid groupId, EntityTypes? memberType);
Task<ListEx<UserResponse>> GetMembersWithInheritedMemberships(string tenantId, Guid groupId, Dictionary<string, string> odata);
Task<IsMemberResponse> IsUserMemberOfGroup(string tenantId, Guid groupId, Guid userId);
Task<GroupResponse> PatchGroup(string tenantId, Guid groupId, JsonPatchDocument<GroupResponse> patchOps);

IApplicationsApi

Task<ApplicationResponse> GetApplication(string tenantId, Guid applicationId);
Task<ListEx<LicenseResponse>> GetLicenses(string tenantId, Guid applicationId, EntityTypes? licenseType);
Task<LicenseResponse> VerifyUserLicense(string tenantId, Guid applicationId, Guid userId);
Task<ListEx<UserLicenseResponse>> GetUsersWithInheritedAccess(string tenantId, Guid applicationId);
Task<LicenseResponse> AddLicense(string tenantId, Guid applicationId, LicenseRequest subscription);
Task<LicenseResponse> SetAccessLevel(string tenantId, Guid applicationId, Guid entityId, EntityTypes? licenseType, string accessLevel);
Task DeleteLicense(string tenantId, Guid applicationId, Guid entityId, EntityTypes? licenseType);
Task<ApplicationResponse> PatchApplication(string tenantId, Guid applicationId, JsonPatchDocument<ApplicationResponse> patchOps);

IElementsApi

Task<PagedList<ElementResponse>> ListElements(string tenantId, Guid applicationId);
Task<ElementResponse> GetElement(string tenantId, Guid applicationId, string elementId);
Task<ElementResponse> CreateElement(string tenantId, Guid applicationId, ElementRequest body);
Task<ElementResponse> CreateChildElement(string tenantId, Guid applicationId, string elementId, ElementRequest body);
Task<ElementResponse> PatchElement(string tenantId, Guid applicationId, string elementId, JsonPatchDocument<ElementResponse> patchDoc);
Task DeleteElement(string tenantId, Guid applicationId, string elementId);
Task<List<ElementRightResponse>> GetElementRights(string tenantId, Guid applicationId, string elementId);
Task<ElementRightResponse> AddElementRights(string tenantId, Guid applicationId, string elementId, ElementRightRequest body);
Task<List<ElementRightTreeResponse>> GetUserElements(string tenantId, Guid applicationId, Guid userId);

Advanced Features

Custom Typed Responses

Create strongly-typed models:

public class MyTenant : TypedTenantBase
{
    public List<string> VesselList
    {
   get => GetValue<List<string>>();
     set => SetValue(value);
    }
 
    public string Department
    {
        get => GetValue<string>();
        set => SetValue(value);
    }
}

// Usage
var typedTenant = await _client.Tenants
    .GetTenant(tenantId)
    .ToTyped<MyTenant>();
    
Console.WriteLine(typedTenant.Department);

OData Queries

var query = new OdataRequest
{
    Filter = "name eq 'John Doe'",
    Search = "engineer",
    OrderBy = new[] 
    { 
      new OrderingElement { Field = "name", Type = OrderTypes.Ascending }
    },
    Top = 25,
    Skip = 0
};

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

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

Extension Properties

// Add/update
var patch = user.MakeJsonPatch()
    .AddOrUpdateProperty("customField", "value")
    .AddOrUpdateProperty("listField", new List<string> { "a", "b" });
await patch.ExecutePatchUserAsync();

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

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

Authorization Attribute

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

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

// Custom configuration
[VeracityAuthorization(
    TenantIdIn = IdCarrierTypes.Path,
    TenantIdKey = "tenant_id",
    CacheWindowSizeInMinutes = 5)]
[HttpGet("api/tenants/{tenant_id}/data")]
public async Task<IActionResult> GetData(string tenant_id)
{
    // Protected endpoint
}

Profile Picture Middleware

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

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

// Programmatic
var imageBytes = await user.GetProfileImage();

Authentication

Authorization Code Flow (Web Apps)

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

Client Credentials Flow (Daemons)

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

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

// Update scope to:
// "https://dnvglb2cprod.onmicrosoft.com/83054ebf-1d7b-43f5-82ad-b2bde84d7b75/.default"

Error Handling

try
{
    var user = await _client.Users.GetUserByEmail(tenantId, email);
}
catch (ServerException ex)
{
  var error = ex.GetErrorData<ErrorDetail>();
    
    _logger.LogError(ex, 
"API error. Correlation ID: {CorrelationId}", 
        error.CorrelationId);
    
return StatusCode((int)ex.Status, new 
    { 
        message = error.Message,
        correlationId = error.CorrelationId
    });
}

Best Practices

1. Caching

services.AddDistributedMemoryCache();
// or
services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = Configuration["Redis:Connection"];
});

2. Logging

public class MyLogger : LogAdapter
{
    private readonly ILogger<MyLogger> _logger;
    
    public MyLogger(ILogger<MyLogger> logger)
    {
 _logger = logger;
    }
    
    protected override void LogMessageInternal(string message, string memberName, int? lineNumber, string filePath)
    {
        _logger.LogInformation("{MemberName} - {Message}", memberName, message);
    }
    
    public override void LogError(Exception exception)
    {
     _logger.LogError(exception, "Veracity API error");
    }
}

services.AddVeracityGraphApi<MyLogger>();

3. Pagination

var allUsers = new List<UserResponse>();
var query = new OdataRequest { Top = 100 };

PagedList<UserResponse> page;
do
{
    page = await _client.Users.ListUsers(tenantId, query);
    allUsers.AddRange(page.Items);
    
    if (page.NextPageUrl != null)
        page = await page.GetNextPage();
    else
        break;
} while (page != null);

4. Bulk Operations

// Good: Batch
var users = await _client.Users.ResolveUsers(tenantId, userIds);

// Bad: Loop
foreach (var userId in userIds)
{
var user = await _client.Users.GetUserInTenant(tenantId, userId);
}

Examples

Complete CRUD Example

public class TenantController : Controller
{
    private readonly IVeracityGraphClient _client;

public TenantController(IVeracityGraphClient client)
    {
 _client = client;
    }

    [VeracityAuthorization]
    [HttpGet("api/tenants/{tenantId}")]
    public async Task<IActionResult> Get(string tenantId)
    {
        try
        {
 var tenant = await _client.Tenants.GetTenant(tenantId);
   return Ok(tenant);
      }
        catch (ServerException ex) when (ex.Status == HttpStatusCode.NotFound)
        {
     return NotFound();
        }
    }

    [VeracityAuthorization("admin")]
  [HttpPatch("api/tenants/{tenantId}")]
    public async Task<IActionResult> Update(string tenantId, [FromBody] Dictionary<string, string> properties)
    {
        var tenant = await _client.Tenants.GetTenant(tenantId);
        var patch = tenant.MakeJsonPatch();
        
 foreach (var prop in properties)
        {
 patch.AddOrUpdateProperty(prop.Key, prop.Value);
        }
      
      var updated = await patch.ExecutePatchTenantAsync();
        return Ok(updated);
    }

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

 [VeracityAuthorization("admin")]
    [HttpPost("api/tenants/{tenantId}/licenses")]
    public async Task<IActionResult> AddLicense(
      string tenantId, 
  [FromBody] LicenseRequest request)
    {
      var license = await _client.ThisApplication.AddLicense(tenantId, request);
        return Created($"/api/licenses/{license.Id}", license);
    }
}

Additional Resources

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 was computed.  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.20251203.3 696 12/3/2025
1.0.20251202.10 681 12/2/2025
1.0.20251202.9 689 12/2/2025
1.0.20241120.7 237 11/20/2024