BllKit 1.0.0
dotnet add package BllKit --version 1.0.0
NuGet\Install-Package BllKit -Version 1.0.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="BllKit" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BllKit" Version="1.0.0" />
<PackageReference Include="BllKit" />
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 BllKit --version 1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: BllKit, 1.0.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 BllKit@1.0.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=BllKit&version=1.0.0
#tool nuget:?package=BllKit&version=1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
BllKit
A lightweight Business Logic Layer toolkit for .NET that eliminates repetitive try/catch boilerplate, standardizes API responses, and provides fluent guard validations.
Compatible with .NET Framework 4.5.2+, .NET Core, .NET 5/6/7/8.
The Problem
Every .NET BLL method ends up looking like this:
// 40 lines — but only 5 lines are actual logic
public async Task<BaseResponse> GetSafetyAlertsByMonth(int orgId, DashboardReportFilter filter)
{
BaseResponse response = new BaseResponse(ResponseStatus.Success);
try
{
OrganisationDBO organisation = await new OrganisationRepo(_conn).GetOrgById(orgId);
if (organisation == null)
{
response.Status = ResponseStatus.Fail;
response.Message = "Organisation not found";
response.HttpStatusCode = 404;
return response;
}
if (filter.FromDate > filter.ToDate)
{
response.Status = ResponseStatus.Error;
response.Message = "Invalid date range";
return response;
}
// actual logic (5 lines)
response.Data = await _repo.GetAlertsAsync(orgId, filter);
}
catch (Exception ex)
{
this.LogError(ex);
response.Status = ResponseStatus.Error;
response.Message = "An unexpected error occurred.";
}
return response;
}
BllKit fixes this.
The Solution
// 8 lines — same result
public async Task<BllResponse> GetSafetyAlertsByMonth(int orgId, DashboardReportFilter filter)
{
return await BllExecutor.TryExecuteAsync(async () =>
{
BllGuard.EnsureNotNull(organisation, "Organisation not found", 404, "ORG_NOT_FOUND");
BllGuard.EnsureDateRangeValid(filter.FromDate, filter.ToDate);
return await _repo.GetAlertsAsync(orgId, filter);
}, ex => this.LogError(ex));
}
Installation
dotnet add package BllKit
Quick Start
1. BllResponse — Standardized Response Model
// Success with data
BllResponse.Success(data);
BllResponse.Success(data, "Records loaded");
// Known business failures
BllResponse.Fail("Organisation not found", errorCode: "ORG_NOT_FOUND", httpStatusCode: 404);
BllResponse.NotFound("Organisation not found", "ORG_NOT_FOUND");
BllResponse.Forbidden("Access denied", "NO_ACCESS");
BllResponse.BadRequest("OrgId is required");
// Unexpected errors
BllResponse.Error("Something went wrong");
// Strongly typed
BllResponse<List<OrderDto>>.Success(orders);
BllResponse<List<OrderDto>>.NotFound("No orders found");
2. BllGuard — Fluent Validations
Guards throw BllGuardException which is automatically caught by BllExecutor and converted to a Fail response — your logger is not called for guard failures.
BllGuard.EnsureNotNull(organisation, "Organisation not found", 404, "ORG_NOT_FOUND");
BllGuard.EnsureNotNullOrEmpty(request.Name, "Name is required");
BllGuard.EnsureNotEmpty(siteIds, "No sites found", 404);
BllGuard.EnsureDateRangeValid(filter.FromDate, filter.ToDate);
BllGuard.EnsureDateRangeProvided(filter.FromDate, filter.ToDate);
BllGuard.EnsureTrue(user.HasAccess, "Access denied", 403, "NO_ACCESS");
BllGuard.EnsurePositive(orgId, "OrgId must be greater than 0");
BllGuard.EnsureInRange(reportType, 1, 3, "Invalid report type");
3. BllExecutor — Try/Catch Wrapper
// Async — returns object data
BllResponse response = await BllExecutor.TryExecuteAsync(
async () => await _repo.GetDataAsync(orgId),
ex => _logger.Error(ex) // optional, your logger
);
// Async — strongly typed
BllResponse<List<Alert>> response = await BllExecutor.TryExecuteAsync<List<Alert>>(
async () => await _repo.GetAlertsAsync(orgId),
ex => _logger.Error(ex)
);
// Async — no return value
BllResponse response = await BllExecutor.TryExecuteAsync(
async () => await _repo.DeleteAsync(id),
ex => _logger.Error(ex)
);
// Sync
BllResponse response = BllExecutor.TryExecute(
() => _repo.GetData(orgId),
ex => _logger.Error(ex)
);
Response Model
public class BllResponse
{
public BllStatus Status { get; } // Success | Fail | Error
public string? Message { get; }
public string? ErrorCode { get; } // e.g. "ORG_NOT_FOUND"
public int HttpStatusCode { get; } // e.g. 200, 404, 500
public object? Data { get; }
public bool IsSuccess { get; }
}
How Errors Are Handled
| Scenario | What happens |
|---|---|
| Operation succeeds | Returns BllResponse.Success(data) |
BllGuard check fails |
Returns BllResponse.Fail(...) — logger NOT called |
| Unexpected exception | Calls your error handler, returns BllResponse.Error() |
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. 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 was computed. 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 was computed. 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 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- No dependencies.
-
.NETStandard 2.1
- No dependencies.
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.0.0 | 104 | 4/29/2026 |