KNM.Core 0.0.1-alpha
KNM.Core
KNM.Core is a shared NuGet infrastructure library for KoNiMa enterprise .NET applications. It eliminates code duplication across projects by providing battle-tested, configurable core services.
Features
| Feature | Description |
|---|---|
| Email Sending | SMTP email with 4 responsive HTML templates + plain-text fallback |
| In-Memory Cache | Prefixed cache keys, absolute + sliding expiration |
| Structured Logging | Database, File, and Application Insights providers |
| Template Rendering | $$PLACEHOLDER$$ substitution engine for HTML/text templates |
| Result Pattern | Result<T> for error handling without exceptions |
| Extension Methods | String, Number, Date, Enum helpers |
Installation
dotnet add package KNM.Core
Quick Start
// Program.cs
builder.Services.AddKnmCore()
.WithCache(cache => {
cache.Prefix = "MYAPP_";
cache.DurationInMinutes = 60;
})
.WithEmail(email => {
email.SmtpHost = "smtp.example.com";
email.SmtpPort = 587;
email.SmtpUser = "user@example.com";
email.SmtpPassword = "password";
email.SmtpDisplayName = "My App";
email.SmtpDisplayEmail = "noreply@example.com";
email.EnableSsl = true;
})
.WithLogger(logger => {
logger.Level = KnmLogLevel.Info;
logger.Provider = KnmLogProvider.File;
logger.FilePath = "logs/app.log";
});
Or via appsettings.json inline configuration:
builder.Services.AddKnmCore(options => {
options.Cache.Prefix = "MYAPP_";
options.Email.SmtpHost = "smtp.example.com";
});
Email Service
Send a simple email
public class MyService(IEmailSenderService emailSender)
{
public async Task SendWelcome(string userEmail, string userName)
{
var dto = new SendMailDto
{
Company = "MyApp",
LogoUrl = "https://myapp.com/logo.png",
Template = EmailTemplate.General,
Recipients = [
new UserEmailSettings
{
Language = "en",
Subject = $"Welcome, {userName}!",
DisplayName = userName,
EmailAddress = userEmail,
Message = new MailMessage
{
Preview = "Welcome to MyApp",
Title = "WELCOME!",
Salutation = $"Dear {userName}",
Message = "Thank you for joining our platform.",
Goodbye = "The MyApp Team"
}
}
]
};
var result = await emailSender.SendAsync(dto);
if (!result.IsSuccess)
Console.WriteLine($"Send failed: {result.Error}");
}
}
Available Templates
| Template | Use case |
|---|---|
EmailTemplate.General |
Basic informational email |
EmailTemplate.WithButton |
Email with a call-to-action button |
EmailTemplate.WithDetailedDetails |
Email with icon + highlighted details block |
EmailTemplate.WithCode |
Email with a prominently displayed OTP/verification code |
Custom Template Override
Supply per-project HTML/TXT files via EmailOptions.TemplateOverrides. When a key is present the renderer loads from disk; otherwise it falls back to the embedded template.
builder.Services.AddKnmCore()
.WithEmail(email => {
email.TemplateOverrides[EmailTemplate.General] =
("wwwroot/emails/General.html", "wwwroot/emails/General.txt");
});
Paths are absolute or relative to the working directory. The file content is cached in memory after the first load, identical to embedded templates.
Cache Service
public class MyService(IAppCache cache)
{
public async Task<User?> GetUser(int id)
{
return await cache.GetOrSetAsync(
key: $"user:{id}",
factory: async () => await db.Users.FindAsync(id),
duration: TimeSpan.FromMinutes(15)
);
}
}
Logger Service
IKnmLogger is a structured application logger with pluggable providers. Configure via WithLogger().
Providers
| Provider | Description |
|---|---|
KnmLogProvider.File |
Daily-rotated log files (e.g. app.2026-03-11.log) |
KnmLogProvider.Database |
Writes to a DbContext via a configurable factory + SaveLogEntry reflection call |
KnmLogProvider.ApplicationInsights |
Sends TraceTelemetry / ExceptionTelemetry to Azure Application Insights |
Configuration
// File provider
.WithLogger(logger => {
logger.Provider = KnmLogProvider.File;
logger.Level = KnmLogLevel.Info;
logger.FilePath = "logs/app.log"; // date suffix added automatically
logger.LogCulture = "en-US"; // language for log messages
});
// Database provider
.WithLogger(logger => {
logger.Provider = KnmLogProvider.Database;
logger.Level = KnmLogLevel.Warning;
logger.DbContextFactory = sp => sp.GetRequiredService<MyAppDbContext>();
// DbContext must expose a SaveLogEntry(string level, string message, ...) method
});
// Application Insights provider
.WithLogger(logger => {
logger.Provider = KnmLogProvider.ApplicationInsights;
logger.AppInsightsConnString = "InstrumentationKey=...";
});
Usage
public class MyService(IKnmLogger logger)
{
public void DoWork()
{
logger.LogInfo("Operation started", action: "DoWork", entity: "MyService");
try { /* ... */ }
catch (Exception ex)
{
logger.LogError("Operation failed", exception: ex, action: "DoWork");
}
}
}
Log methods
| Method | Level |
|---|---|
LogInfo(message, ...) |
Information |
LogWarning(message, ...) |
Warning |
LogError(message, exception?, ...) |
Error |
LogCritical(message, exception?, ...) |
Critical |
Result Pattern
// Return Result<T> from your methods
public Result<User> GetUser(int id)
{
var user = db.Users.Find(id);
return user is null
? Result<User>.Failure("User not found", "USER_404")
: Result<User>.Success(user);
}
// Consume with chaining
var result = GetUser(42)
.Map(user => user.Email)
.Map(email => email.ToLower());
if (result.IsSuccess)
Console.WriteLine(result.Value);
else
Console.WriteLine($"Error [{result.ErrorCode}]: {result.Error}");
HttpClient Extensions
HttpClientExtensions wraps any HttpClient with automatic Polly retry and a configurable per-request timeout. All methods return Result<T> or Result.
| Method | Description |
|---|---|
GetWithRetryAsync<T>(url, retries, timeout) |
GET → deserialize JSON to T |
PostWithRetryAsync<T>(url, body, retries, timeout) |
POST JSON body → deserialize response |
PutWithRetryAsync<T>(url, body, retries, timeout) |
PUT JSON body → deserialize response |
DeleteWithRetryAsync(url, retries, timeout) |
DELETE → Result |
Retry policy: exponential backoff with jitter, triggers on HttpRequestException and HTTP 500/502/503/504/408.
var result = await httpClient.GetWithRetryAsync<WeatherData>(
url: "https://api.example.com/weather/rome",
retries: 3,
timeout: TimeSpan.FromSeconds(10));
if (result.IsSuccess)
Console.WriteLine(result.Value!.Temperature);
else
Console.WriteLine($"[{result.ErrorCode}] {result.Error}");
Extension Methods
String
"hello world".Truncate(8); // "hello..."
"User@Example.COM".NormalizeEmail(); // "user@example.com"
"<b>Hello</b>".ToCleanText(); // "Hello"
myObject.ToJson(indent: true); // pretty JSON
"{\"name\":\"Alice\"}".FromJson<User>(); // User object
Number
1234.56m.ToCurrency("it-IT"); // "€ 1.234,56"
1234.5678m.RoundBankers(2); // 1234.57
1_500_000L.ToHumanReadable(); // "1.5M"
Date
DateTime.Now.ToShortDate(); // "11/03/2026" (default: it-IT)
DateTime.Now.ToShortDate("en-US"); // "3/11/2026"
DateTime.Now.ToFormattedDate("yyyy-MM-dd"); // "2026-03-11"
DateTime.Now.ToIso8601(); // "2026-03-11T10:00:00.000Z"
new DateTime(1990, 5, 15).GetAge(); // 35
DateTime.Now.ToUnixTimestamp(); // Unix epoch seconds
DateTime.Now.IsWeekend(); // false
DateTime.Now.StartOfMonth(); // 2026-03-01
DateTime.Now.EndOfMonth(); // 2026-03-31
Enum
MyEnum.SomeValue.GetDescription(); // reads [Description] attribute
"Active".TryParse<StatusEnum>(); // StatusEnum? (null-safe)
Architecture
KNM.Core/
├── Models/ DTOs, enums, CoreOptions, Result<T>
├── Services/
│ ├── Interfaces/ IEmailSenderService, IAppCache, ITemplateRenderer, IKnmLogger
│ └── ... Concrete implementations
├── Extensions/ StringExtensions, NumberExtensions, DateExtensions, EnumExtensions
├── Templates/ Embedded HTML + TXT email templates
├── Resources/ Localized strings (en-US default, it-IT, es-ES, fr-FR, de-DE)
└── Internal/ EmailInternal (not public API)
Requirements
- .NET 10+
- Microsoft.Extensions.Caching.Memory
- Microsoft.Extensions.DependencyInjection.Abstractions
- Microsoft.Extensions.Logging.Abstractions
License
MIT — KoNiMa S.r.l.
Showing the top 20 packages that depend on KNM.Core.
| Packages | Downloads |
|---|---|
|
KNM.Reporting
Unified reporting abstraction supporting SSRS, FastReport, QuestPDF, and ClosedXML with fluent DI configuration
|
1 |
|
KNM.Reporting
Unified reporting abstraction supporting SSRS, FastReport, QuestPDF, and ClosedXML with fluent DI configuration
|
2 |
|
KNM.Reporting.Designer
Plug and play Blazor admin panel for report generation, management, and monitoring in the KoNiMa ecosystem
|
0 |
.NET 10.0
- Microsoft.ApplicationInsights (>= 2.22.0)
- Microsoft.Extensions.Caching.Memory (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Logging (>= 10.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Options (>= 10.0.0)
- Polly (>= 8.6.6)
| Version | Downloads | Last updated |
|---|---|---|
| 1.5.0 | 3 | 30/03/2026 |
| 1.4.0 | 3 | 29/03/2026 |
| 1.3.1 | 4 | 26/03/2026 |
| 1.3.0 | 0 | 26/03/2026 |
| 1.2.0 | 4 | 25/03/2026 |
| 0.0.2-alpha | 2 | 12/03/2026 |
| 0.0.1-alpha | 1 | 11/03/2026 |