ProvisionData.Common
4.0.18
See the version list below for details.
dotnet add package ProvisionData.Common --version 4.0.18
NuGet\Install-Package ProvisionData.Common -Version 4.0.18
<PackageReference Include="ProvisionData.Common" Version="4.0.18" />
<PackageVersion Include="ProvisionData.Common" Version="4.0.18" />
<PackageReference Include="ProvisionData.Common" />
paket add ProvisionData.Common --version 4.0.18
#r "nuget: ProvisionData.Common, 4.0.18"
#:package ProvisionData.Common@4.0.18
#addin nuget:?package=ProvisionData.Common&version=4.0.18
#tool nuget:?package=ProvisionData.Common&version=4.0.18
ProvisionData.Common
A selection of useful classes and utilities commonly used in software by Provision Data Systems Inc.
Installation
You can install the ProvisionData.Common package via NuGet Package Manager Console:
Install-Package ProvisionData.Common
Or via .NET CLI:
dotnet add package ProvisionData.Common
Features
- Result Pattern for handling operation outcomes
- Safe IAsyncDisposable and IDisposable pattern
Result Pattern
The Result class provides a way to represent the outcome of operations,
encapsulating success and failure states along with relevant data or error messages.
Basic Usage
public class UserService
{
private readonly IUserRepository _repository;
public Result<User> GetById(int id)
{
var user = _repository.Find(id);
if (user is null)
return Error.NotFound("User.NotFound", $"User with ID {id} was not found");
return user; // Implicit conversion to Result<User>.Success
}
public Result<User> Create(CreateUserRequest request)
{
// Validation
if (string.IsNullOrWhiteSpace(request.Email))
return Error.Validation("User.EmailRequired", "Email is required");
if (_repository.ExistsByEmail(request.Email))
return Error.Conflict("User.EmailExists", "A user with this email already exists");
// Create user
var user = new User(request.Name, request.Email);
_repository.Add(user);
return user;
}
}```
#### Chaining Operations
```csharp
public Result<OrderConfirmation> ProcessOrder(CreateOrderRequest request)
{
return ValidateOrder(request)
.Bind(order => CheckInventory(order))
.Bind(order => ProcessPayment(order))
.Bind(order => CreateShipment(order))
.Map(shipment => new OrderConfirmation(shipment.TrackingNumber));
}
private Result<Order> ValidateOrder(CreateOrderRequest request)
{
if (request.Items.Count == 0)
return Error.Validation("Order.NoItems", "Order must contain at least one item");
return new Order(request.CustomerId, request.Items);
}
private Result<Order> CheckInventory(Order order)
{
foreach (var item in order.Items)
{
if (!_inventory.IsAvailable(item.ProductId, item.Quantity))
return Error.Conflict("Order.OutOfStock", $"Product {item.ProductId} is out of stock");
}
return order;
}
Using Match
var message = userService.GetById(userId).Match(
onSuccess: user => $"Welcome, {user.Name}!",
onFailure: error => $"Error: {error.Description}"
);
Domain Errors
public static class DomainErrors
{
public static class User
{
public static Error NotFound(int id) =>
Error.NotFound("User.NotFound", $"User with ID {id} was not found");
public static Error EmailAlreadyExists(string email) =>
Error.Conflict("User.EmailExists", $"Email {email} is already registered");
public static Error InvalidEmail =>
Error.Validation("User.InvalidEmail", "The email format is invalid");
public static Error PasswordTooWeak =>
Error.Validation("User.PasswordTooWeak",
"Password must be at least 8 characters with uppercase, lowercase, and digits");
}
public static class Order
{
public static Error NotFound(Guid id) =>
Error.NotFound("Order.NotFound", $"Order {id} was not found");
public static Error EmptyCart =>
Error.Validation("Order.EmptyCart", "Cannot create order with empty cart");
public static Error InsufficientStock(string productId) =>
Error.Conflict("Order.InsufficientStock", $"Insufficient stock for product {productId}");
public static Error PaymentFailed(string reason) =>
Error.Failure("Order.PaymentFailed", $"Payment failed: {reason}");
}
}
Web API Integration
This is packaged separately in ProvisionData.WebApi so you need to install that package as well.
Install-Package ProvisionData.Common
Or via .NET CLI:
dotnet add package ProvisionData.Common
Once installed, you can use the extension methods to convert Result instances to appropriate HTTP responses.
var app = builder.Build();
app.MapGet("/api/users/{id}", (int id, UserService userService) =>
{
return userService.GetById(id).ToApiResult();
});
app.MapPost("/api/users", (CreateUserRequest request, UserService userService) =>
{
return userService.Create(request)
.ToCreatedResult($"/api/users/{request.Email}");
});
app.MapPost("/api/orders", (CreateOrderRequest request, OrderService orderService) =>
{
return orderService.ProcessOrder(request).Match(
onSuccess: confirmation => Results.Ok(confirmation),
onFailure: error => error switch
{
ValidationError => Results.BadRequest(new { error.Code, error.Description }),
ConflictError => Results.Conflict(new { error.Code, error.Description }),
_ => Results.Problem(error.Description)
}
);
});
Safe IAsyncDisposable and IDisposable pattern
public class MyTestFixture : DisposableBase
{
private HttpClient? _httpClient; // IDisposable only
private DbConnection? _dbConnection; // IAsyncDisposable
protected override void Dispose(Boolean disposing)
{
if (disposing)
{
_httpClient?.Dispose();
_httpClient = null;
}
base.Dispose(disposing);
}
protected override async ValueTask DisposeAsyncCore()
{
if (_dbConnection is not null)
{
await _dbConnection.DisposeAsync().ConfigureAwait(false);
_dbConnection = null;
}
// HttpClient also implements IAsyncDisposable in modern .NET
if (_httpClient is IAsyncDisposable asyncDisposable)
{
await asyncDisposable.DisposeAsync().ConfigureAwait(false);
}
else
{
_httpClient?.Dispose();
}
_httpClient = null;
await base.DisposeAsyncCore().ConfigureAwait(false);
}
}
How does a derived class know which dispose to override?
| Scenario | Override |
|---|---|
Async resources (e.g., IAsyncDisposable fields, async streams) |
DisposeAsyncCore() |
Sync-only resources (e.g., IDisposable fields, unmanaged handles) |
Dispose(Boolean) |
| Mixed resources | Both methods |
The key insight: when DisposeAsync() is called, it calls DisposeAsyncCore() first (cleaning
managed resources async), then Dispose(false) (cleaning only unmanaged resources). This
prevents double-disposal of managed resources.
| Product | Versions 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. |
-
net10.0
- No dependencies.
NuGet packages (4)
Showing the top 4 NuGet packages that depend on ProvisionData.Common:
| Package | Downloads |
|---|---|
|
ProvisionData.Testing.Integration
Basic classes and utilities used across all PDSI projects. |
|
|
ProvisionData.WebApi
Enables using the Result pattern in ASP.NET Core applications. |
|
|
ProvisionData.AspNetCore
Basic classes and utilities used across all PDSI projects. |
|
|
ProvisionData.Testing.Integration.Examples
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.21 | 0 | 2/4/2026 |
| 4.0.19 | 0 | 2/3/2026 |
| 4.0.18 | 40 | 2/2/2026 |
| 4.0.17 | 33 | 1/31/2026 |
| 4.0.15 | 33 | 1/30/2026 |
| 4.0.4 | 70 | 1/29/2026 |
| 4.0.3 | 76 | 1/29/2026 |
| 4.0.2 | 84 | 1/28/2026 |
| 4.0.1 | 79 | 1/28/2026 |
| 3.1.0 | 572 | 10/22/2021 |
| 3.0.0 | 671 | 9/25/2021 |
| 2.3.2 | 289 | 5/9/2020 |
| 2.3.1 | 1,064 | 2/28/2020 |
| 2.3.0 | 1,059 | 2/25/2020 |
| 2.2.2 | 1,072 | 1/16/2020 |
| 2.2.1 | 1,079 | 11/23/2019 |
| 2.2.0 | 1,107 | 11/13/2019 |
| 2.1.1 | 1,084 | 11/13/2019 |
| 2.1.0 | 1,116 | 11/12/2019 |
| 1.4.0 | 921 | 10/17/2019 |
| 1.3.0 | 898 | 10/15/2019 |
| 1.2.16 | 632 | 10/8/2019 |
| 1.2.15 | 685 | 9/21/2019 |
| 1.1.11 | 721 | 9/21/2019 |
| 1.1.10 | 736 | 8/29/2019 |
| 1.1.7 | 693 | 8/27/2019 |
| 1.0.2 | 759 | 5/3/2019 |
| 1.0.1 | 772 | 5/3/2019 |