BauerApps.Dataverse.Extensions.DependencyInjection 1.2.0

dotnet add package BauerApps.Dataverse.Extensions.DependencyInjection --version 1.2.0
                    
NuGet\Install-Package BauerApps.Dataverse.Extensions.DependencyInjection -Version 1.2.0
                    
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="BauerApps.Dataverse.Extensions.DependencyInjection" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BauerApps.Dataverse.Extensions.DependencyInjection" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="BauerApps.Dataverse.Extensions.DependencyInjection" />
                    
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 BauerApps.Dataverse.Extensions.DependencyInjection --version 1.2.0
                    
#r "nuget: BauerApps.Dataverse.Extensions.DependencyInjection, 1.2.0"
                    
#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 BauerApps.Dataverse.Extensions.DependencyInjection@1.2.0
                    
#: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=BauerApps.Dataverse.Extensions.DependencyInjection&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=BauerApps.Dataverse.Extensions.DependencyInjection&version=1.2.0
                    
Install as a Cake Tool

Dataverse.Extensions.DependencyInjection

CI NuGet NuGet Downloads License

Dependency injection extensions for Microsoft.PowerPlatform.Dataverse.Client. Registers a singleton ServiceClient and a scoped IOrganizationServiceAsync2 (via Clone()) with a single method call.

Features

  • One-line DI registration for ServiceClient with proper singleton + scoped Clone() lifecycle
  • Keyed (multi-environment) client registration via native .NET keyed DI
  • Authentication via Azure.Identity (DefaultAzureCredential by default, any TokenCredential supported)
  • Automatic logger wiring from the DI container
  • Options validation at startup — fail fast on misconfiguration
  • Targeted at ASP.NET Core and Azure Functions

Get started

Install the package from NuGet:

dotnet add package BauerApps.Dataverse.Extensions.DependencyInjection

Register the client in Program.cs:

builder.Services.AddDataverseClient(options =>
{
    options.OrganizationUrl = new Uri("https://my-org.crm4.dynamics.com");
});

Inject IOrganizationServiceAsync2 anywhere:

public class AccountsController(IOrganizationServiceAsync2 dataverse) : ControllerBase
{
    [HttpGet("{id:guid}")]
    public async Task<IActionResult> Get(Guid id)
    {
        var entity = await dataverse.RetrieveAsync("account", id,
            new ColumnSet("name", "revenue"));
        return Ok(entity);
    }
}

Configuration

Configure via DataverseClientOptions:

Option Required Default Description
OrganizationUrl Base URL of your Dataverse environment (e.g. https://my-org.crm4.dynamics.com)
TokenCredential DefaultAzureCredential Custom TokenCredential for authentication. Supports any Azure.Identity credential.
DeferConnection false When true, connection to Dataverse is deferred until first use.

Authentication examples

Default (system-assigned managed identity / local dev):

builder.Services.AddDataverseClient(options =>
{
    options.OrganizationUrl = new Uri("https://my-org.crm4.dynamics.com");
});

User-assigned managed identity:

builder.Services.AddDataverseClient(options =>
{
    options.OrganizationUrl = new Uri("https://my-org.crm4.dynamics.com");
    options.TokenCredential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
    {
        ManagedIdentityClientId = "d0f19fa6-76ef-46cb-93ac-fcde5a4a6143"
    });
});

Client secret:

builder.Services.AddDataverseClient(options =>
{
    options.OrganizationUrl = new Uri("https://my-org.crm4.dynamics.com");
    options.TokenCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
});

Environment-specific configuration

Bind the options directly from a configuration section:

// appsettings.Production.json
{
  "Dataverse": {
    "OrganizationUrl": "https://my-org-prod.crm4.dynamics.com",
    "DeferConnection": false
  }
}
builder.Services.AddDataverseClient(builder.Configuration.GetSection("Dataverse"));

Only non-secret values bind from configuration. Authentication uses DefaultAzureCredential by default; to supply a custom credential, layer it on with the options pattern:

builder.Services.AddDataverseClient(builder.Configuration.GetSection("Dataverse"));
builder.Services.PostConfigure<DataverseClientOptions>(options =>
    options.TokenCredential = new ClientSecretCredential(tenantId, clientId, clientSecret));

Keyed clients (multiple environments)

Use keyed registration when your application needs to connect to more than one Dataverse environment — for example a data migration that reads from a source org and writes to a target org.

Register each client with a string key:

builder.Services.AddDataverseClient("source", options =>
{
    options.OrganizationUrl = new Uri("https://source.crm4.dynamics.com");
});

builder.Services.AddDataverseClient("target",
    builder.Configuration.GetSection("Dataverse:Target"));

Resolve via [FromKeyedServices]:

public sealed class MigrationService(
    [FromKeyedServices("source")] IOrganizationServiceAsync2 source,
    [FromKeyedServices("target")] IOrganizationServiceAsync2 target)
{
    public async Task MigrateAsync()
    {
        // read from source, write to target
    }
}

Each keyed registration is fully independent — its own singleton ServiceClient and its own scoped IOrganizationServiceAsync2. Keyed and unkeyed registrations coexist without conflict.

Why scoped IOrganizationServiceAsync2?

ServiceClient is registered as a singleton to share the underlying connection, metadata cache, and authentication token. However, using a single instance across concurrent requests can cause subtle threading issues.

Clone() creates a lightweight copy that shares the parent's connection pool but is safe for per-request use. This library registers IOrganizationServiceAsync2 as scoped, so each request gets its own clone automatically.

License

MIT

Product Compatible and additional computed target framework versions.
.NET 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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 0 6/20/2026
1.1.0 90 6/15/2026
1.0.0 90 6/13/2026