Rasmio.Corelib
10.12.0
dotnet add package Rasmio.Corelib --version 10.12.0
NuGet\Install-Package Rasmio.Corelib -Version 10.12.0
<PackageReference Include="Rasmio.Corelib" Version="10.12.0" />
<PackageVersion Include="Rasmio.Corelib" Version="10.12.0" />
<PackageReference Include="Rasmio.Corelib" />
paket add Rasmio.Corelib --version 10.12.0
#r "nuget: Rasmio.Corelib, 10.12.0"
#:package Rasmio.Corelib@10.12.0
#addin nuget:?package=Rasmio.Corelib&version=10.12.0
#tool nuget:?package=Rasmio.Corelib&version=10.12.0
Rasmio.Corelib
Shared infrastructure library for Rasmio services. It bundles the cross-cutting building blocks used
across our ASP.NET Core apps — notifications (SMS/email), rate limiting, JWT / API-key security,
CQRS + MediatR behaviors, object storage, and a set of integration helpers — behind a small number of
IServiceCollection extension methods.
Targets .NET 10 (
net10.0).
Install
dotnet add package Rasmio.Corelib
Configuration
The library ships no appsettings.json; every secret and setting is supplied by the consuming
application's configuration (appsettings.json, environment variables, user secrets, key vault, …).
No credentials are compiled into the assembly.
Each module binds its own configuration section. The main ones:
| Module | Entry point | Config section |
|---|---|---|
| Notifications (SMS/email, multi-provider) | AddRasmioNotifications(IConfiguration) |
Notifications |
Legacy helpers (StaticHelpers, PayPing) |
AddRasmioLegacyHelpers(IConfiguration) |
RasmioLegacyHelpers |
| JWT authentication | AddJWTAutentication(IConfiguration) |
SecuritySettings |
| Rate limiting | AddRateLimiting(IConfiguration) |
see RateLimit/README.md |
Notifications (recommended)
The modern, DI-first notification module. Register it and inject IEmailSender / ISmsSender:
builder.Services.AddRasmioNotifications(builder.Configuration);
{
"Notifications": {
"ActiveSmsProviders": [ "Asiatech", "Kavenegar" ],
"ActiveEmailProviders": [ "Smtp" ],
"Sms": {
"Kavenegar": { "ApiKey": "<key>" },
"Asiatech": { "AuthorizationHeader": "Basic <base64>", "SourceAddress": "9890004043" }
},
"Email": {
"SendGrid": { "ApiKey": "SG.xxxx" },
"Smtp": { "Host": "smtp.example.com", "Port": 587, "Username": "u", "Password": "p" }
}
}
}
Legacy static helpers
Rasmio.Corelib.Helpers.StaticHelpers (SMS/email/Bale) and the PayPing payment transport predate the
notification module and expose static methods. They now read their credentials from configuration
instead of hardcoded values. Wire them once at startup:
builder.Services.AddRasmioLegacyHelpers(builder.Configuration);
{
"RasmioLegacyHelpers": {
"AsiatechAuthorizationHeader": "Basic <base64 of user:pass>",
"AsiatechSourceAddress": "9890004043",
"KavenegarApiKey": "<kavenegar-key>",
"SendGridApiKey": "SG.xxxx",
"BaleBotToken": "1337708678:xxxx",
"BaleDefaultChatId": 1463410933,
"BaleSafirApiAccessKey": "xxxx",
"BaleSafirBotId": 502457471,
"PayPingToken": "xxxx"
}
}
In containers/cloud you can skip appsettings.json entirely and set environment variables using the
standard double-underscore convention — these are read even without calling AddRasmioLegacyHelpers:
RasmioLegacyHelpers__KavenegarApiKey=...
RasmioLegacyHelpers__SendGridApiKey=...
RasmioLegacyHelpers__PayPingToken=...
User-facing helpers (SMSAsync, AsiatechOTP, SMSToArray, Email, SendBaleOTPAsync) throw a clear
InvalidOperationException when a required secret is missing; the fire-and-forget BaleAsync diagnostic
alert silently no-ops when its bot token is not configured.
New code should prefer
IEmailSender/ISmsSenderfromAddRasmioNotificationsover the static helpers.
Release notes
10.12.0
Logging, Sentry and privacy changes. No public member was removed; the behavior changes below are what a consumer notices after upgrading.
Additions: BusinessException(string? message, Exception? innerException), so a rejection can keep
its cause.
Notifications: CompositeSmsSender / CompositeEmailSender log the recipient masked (***1234,
a***@example.com) instead of in full, and record rasmio.sms.sends / rasmio.email.sends
(tags provider, outcome = sent|failed) on the meter Rasmio.Corelib.Notifications; subscribe with
AddMeter("Rasmio.Corelib.Notifications") or AddMeter("Rasmio.Corelib.*").
GlobalExceptionHandlerMiddleware
- Logged by the status it answers with. An exception answered with a 4xx (FluentValidation
ValidationException,BusinessException,ServiceException,ForbiddenException,PackageExpiredException,NotEnoughCreditsException, anAppExceptionwhoseHttpStatusCodeis below 500,UnauthorizedAccessException) is one Information line,Request {CorrelationId} answered {StatusCode} for {ExceptionType}(plus{ApiStatusCode}for anAppException), with no exception object (no stack trace) and no exception message. It is not sent to Sentry, so a 4xx response no longer carriessentryTraceId; response bodies are otherwise unchanged. A 5xx is one Error with the exception,Request {CorrelationId} failed with unhandled {ExceptionType}, and a Sentry event as before. UnauthorizedAccessExceptionis logged once (it was logged twice, at Error, with its Persian message as the template).- The request-body log is gone. The per-request
Request {CorrelationId}: {Method} {Path} {QueryString} Body: {Body}line, theEnableBuffering()call and the body read are removed; the request body is no longer buffered or read. The response log, which never ran, is removed too. - Client aborts are 499. An
OperationCanceledExceptionwhileRequestAbortedis signalled is one Information line (client closed the request) and status 499 with no body, instead of an Error, a 500 and a Sentry event. The 60-second timeout branch is unchanged. - Correlation. Each request runs in a logging scope carrying
CorrelationId(every logger of the factory sees it) and tags its span withapp.correlation_id. An incomingX-Correlation-IDis kept only when it is at most 64 characters of[A-Za-z0-9._-]; otherwise a new id is generated and returned. Exception log lines also carryUserIdin their scope for a signed-in user. - Sentry events carry no IP, query string, username or claims. The
client_ip,x-forwarded-forandqueryextras are gone; forwarding headers (X-Forwarded-For,X-Real-IP,Forwardedand Rasmio's own IP headers) are dropped from theheadersextra; the Sentry user is the internal user id with onlyUserPackageIdandRoles.
SentryUserMiddleware: the Sentry user is the internal user id (the client fingerprint for an
anonymous caller); no username, email or IP address.
UseRasmioSentry
- Sampling honors
Sentry:TracesSampleRate. The sampler returned 1.0 for every transaction, so the configured rate had no effect. It now returns the configured rate (default when unset: 1.0 in Production, 0.5 elsewhere), and still 0 for transactions whose name containshealth. MaxBreadcrumbsis 100 (was 400), against413 Payload Too Largerejections.- Sentry Logs are off unless
Sentry:EnableLogs=true(newSentryConfiguration.EnableLogs). Logs already reach Loki through the OpenTelemetry collector. - Environment names change case. The environment is
Sentry:Environmentwhen set, otherwise the host environment name in lower case (production,staging,qa,development), matching the environments the release pipeline creates. Sentry searches, alerts and dashboards that filter onProduction,StagingorDevelopmentneed updating. - Exception filters.
AppExceptionis dropped only when itsHttpStatusCodeis below 500: anAppExceptionanswered with a 5xx is now reported.ValidationException,ServiceException,ForbiddenExceptionandPackageExpiredExceptionare now filtered too, so a 4xx cannot become an event through another path. Note that someAppExceptionconstructor overloads leaveHttpStatusCodeat 500 (for examplenew NotFoundException()andnew NotFoundException(message, innerException)); the middleware answers those with a 500, so they are now logged as Errors and sent to Sentry.
Rate limiting: spans no longer carry ratelimit.ip_address; ratelimit.client_identifier keeps
user:<id> but reduces ip:<address> and fingerprint:<value> to ip and fingerprint. The
limiter's log lines, its Sentry report (no username, IP address, claims or query string) and the DNS
verification logs no longer carry the caller's IP address. Redis keys are unchanged.
AddCustomRedis: IDistributedCache now uses the IConnectionMultiplexer registered in DI
(resolved lazily), so a host that replaces that registration has one connection, and its Redis
instrumentation sees the cache's traffic. The connection registered here uses
AbortOnConnectFail = false, as the cache's own connection always did. Do not enable the
Microsoft.AspNetCore.Caching.StackExchangeRedis.UseForceReconnect AppContext switch with it.
License
| 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
- Asp.Versioning.Mvc (>= 10.2.1)
- AspNetCore.HealthChecks.Rabbitmq (>= 9.0.0)
- AspNetCore.HealthChecks.Redis (>= 9.0.0)
- AspNetCore.HealthChecks.SqlServer (>= 9.0.0)
- AspNetCore.HealthChecks.UI (>= 9.0.0)
- AspNetCore.HealthChecks.UI.Client (>= 9.0.0)
- AspNetCore.HealthChecks.UI.InMemory.Storage (>= 9.0.0)
- AWSSDK.S3 (>= 4.0.102.5)
- brevo_csharp (>= 1.1.3)
- ClosedXML (>= 0.105.1)
- Dapper (>= 2.1.79)
- Elasticsearch.Net (>= 7.17.5)
- FluentResults (>= 4.0.0)
- FluentValidation (>= 12.1.1)
- Google.Protobuf (>= 3.36.1)
- Grpc.AspNetCore (>= 2.83.0)
- Grpc.AspNetCore.Server.Reflection (>= 2.83.0)
- Hangfire.AspNetCore (>= 1.8.25)
- Hangfire.Core (>= 1.8.25)
- Hangfire.InMemory (>= 1.0.0)
- Hangfire.SqlServer (>= 1.8.25)
- IdeaTech.SemanticKernel.Connectors.Ollama (>= 1.0.3)
- IdentityModel (>= 7.0.0)
- KubernetesClient (>= 19.0.2)
- MassTransit (= 8.5.7)
- MassTransit.EntityFrameworkCore (= 8.5.7)
- MassTransit.RabbitMQ (= 8.5.7)
- MediatR (= 12.5.0)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.11)
- Microsoft.AspNetCore.DataProtection.StackExchangeRedis (>= 10.0.11)
- Microsoft.AspNetCore.Identity.EntityFrameworkCore (>= 10.0.11)
- Microsoft.AspNetCore.OpenApi (>= 10.0.11)
- Microsoft.EntityFrameworkCore (>= 10.0.11)
- Microsoft.EntityFrameworkCore.SqlServer (>= 10.0.11)
- Microsoft.Extensions.Caching.StackExchangeRedis (>= 10.0.11)
- Microsoft.Extensions.Configuration (>= 10.0.11)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Configuration.Json (>= 10.0.11)
- Microsoft.Extensions.DependencyInjection (>= 10.0.11)
- Microsoft.Extensions.Hosting (>= 10.0.11)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Options (>= 10.0.11)
- Microsoft.SemanticKernel (>= 1.80.1)
- Microsoft.VisualStudio.Azure.Containers.Tools.Targets (>= 1.23.0)
- MongoDB.Bson (>= 3.11.1)
- MongoDB.Driver (>= 3.11.1)
- Neo4j.Driver (>= 6.3.0)
- NEST (>= 7.17.5)
- OpenGraph-Net (>= 4.0.1)
- OpenTelemetry (>= 1.18.0)
- OpenTelemetry.Exporter.Prometheus.AspNetCore (>= 1.18.0-beta.1)
- OpenTelemetry.Extensions.Hosting (>= 1.18.0)
- OpenTelemetry.Instrumentation.AspNetCore (>= 1.18.0)
- OpenTelemetry.Instrumentation.EntityFrameworkCore (>= 1.15.1-beta.1)
- OpenTelemetry.Instrumentation.Http (>= 1.18.0)
- OpenTelemetry.Instrumentation.Process (>= 1.15.1-beta.1)
- OpenTelemetry.Instrumentation.Runtime (>= 1.18.0)
- OpenTelemetry.Instrumentation.StackExchangeRedis (>= 1.15.1-beta.2)
- Polly (>= 8.7.0)
- RedisRateLimiting.AspNetCore (>= 1.2.1)
- RedLock.net (>= 2.3.2)
- RestSharp (>= 114.0.0)
- Scalar.AspNetCore (>= 2.17.2)
- Scrutor (>= 7.0.0)
- SendGrid (>= 9.29.3)
- Sentry.AspNetCore (>= 6.10.0)
- Sentry.DiagnosticSource (>= 6.10.0)
- Sentry.Extensions.Logging (>= 6.10.0)
- Sentry.Hangfire (>= 6.10.0)
- Sentry.OpenTelemetry (>= 6.10.0)
- Sentry.Profiling (>= 6.10.0)
- Serilog (>= 4.4.0)
- Serilog.Extensions.Hosting (>= 10.0.0)
- Serilog.Sinks.MSSqlServer (>= 10.0.0)
- Sieve (>= 2.5.5)
- Slack.NetStandard (>= 11.6.0)
- Swashbuckle.AspNetCore (>= 10.2.3)
- Swashbuckle.AspNetCore.SwaggerGen (>= 10.2.3)
- System.IdentityModel.Tokens.Jwt (>= 8.22.0)
- System.ServiceModel.Http (>= 10.0.652802)
- UAParser (>= 3.1.47)
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 |
|---|---|---|
| 10.12.0 | 0 | 9/29/2026 |
| 10.11.1 | 101 | 9/16/2026 |
| 10.11.0 | 81 | 9/12/2026 |
| 10.10.0 | 103 | 9/10/2026 |
| 10.9.3 | 79 | 9/9/2026 |
| 10.9.2 | 126 | 9/6/2026 |
| 10.9.1 | 79 | 9/6/2026 |
| 10.9.0 | 320 | 7/25/2026 |
| 10.8.1 | 219 | 7/21/2026 |
| 10.8.0 | 87 | 7/21/2026 |
| 10.7.1 | 86 | 7/21/2026 |
| 10.7.0 | 74 | 7/20/2026 |
| 10.6.4 | 100 | 7/20/2026 |
| 10.6.3 | 144 | 7/19/2026 |
| 10.6.2 | 86 | 7/19/2026 |
| 10.6.1 | 95 | 7/19/2026 |
| 10.6.0 | 82 | 7/19/2026 |