Messages and Message Types
Understanding the Message structure and types is fundamental to using EasyMessages effectively.
Table of contents
What is a Message?
A Message in EasyMessages is an immutable record that represents a standardized communication about an operation, event, or state in your application.
var message = Msg.Auth.LoginFailed();
// Message is a sealed record - immutable and thread-safe
Console.WriteLine(message.Code); // "AUTH_001"
Console.WriteLine(message.Type); // MessageType.Error
Console.WriteLine(message.Title); // "Authentication Failed"
Console.WriteLine(message.Description); // "Invalid username or password."
Message Structure
Every message consists of three main parts: Identity, Content, and Context.
1. Identity Properties
These uniquely identify the message:
public sealed record Message
{
public string Code { get; init; } // e.g., "AUTH_001"
public MessageType Type { get; init; } // Success, Info, Warning, Error, Critical
}
Code Format: PREFIX_NNN
- PREFIX: Category identifier (3-6 uppercase letters)
AUTH- AuthenticationCRUD- CRUD operationsVAL- ValidationSYS- SystemDB- DatabaseFILE- File operationsNET- Network- And more…
- NNN: Sequential number (001-999)
2. Content Properties
These describe what the message is about:
public string Title { get; init; } // Short summary
public string Description { get; init; } // Detailed explanation
public string? Hint { get; init; } // Optional suggestion/guidance
Example:
var message = Msg.Validation.RequiredField("Email");
// Title: "Required Field Missing"
// Description: "Email is required."
// Hint: null (or could be "Please provide a valid email address")
3. Context Properties
These provide additional information about when and where:
public DateTime Timestamp { get; init; } // When created (UTC)
public string? CorrelationId { get; init; } // For distributed tracing
public int? HttpStatusCode { get; init; } // Suggested HTTP status
4. Data Properties
These carry custom information:
public object? Data { get; init; } // Payload data
public Dictionary<string, object?> Parameters { get; init; } // Template parameters
public Dictionary<string, object> Metadata { get; init; } // Additional context
Example:
var message = Msg.Crud.Created("User")
.WithData(new { Id = 123, Name = "John" })
.WithMetadata("source", "API")
.WithMetadata("ipAddress", "192.168.1.1")
.WithCorrelationId("abc-123");
Message Types
EasyMessages defines 5 message types that indicate severity and purpose:
public enum MessageType
{
Success = 0, // Operation succeeded
Info = 1, // Informational message
Warning = 2, // Warning - something needs attention
Error = 3, // Error - operation failed
Critical = 4 // Critical - system integrity affected
}
Success (MessageType.Success)
Purpose: Indicate successful operations
Characteristics:
- [✓] Operation completed successfully
- [✓] Positive outcome
- [✓] User action worked as intended
- [✓] Typically logged at Information level
HTTP Status Codes: Usually 200-299 (2xx Success)
Examples:
Msg.Auth.LoginSuccessful() // Type: Success, HTTP: 200
Msg.Crud.Created("Product") // Type: Success, HTTP: 200
Msg.Crud.Updated("User") // Type: Success, HTTP: 200
Msg.System.OperationCompleted() // Type: Success, HTTP: 200
Console Output: Green ✓
When to Use:
- User successfully logs in
- Resource created/updated/deleted
- File uploaded successfully
- Payment processed
- Data imported
Info (MessageType.Info)
Purpose: Provide informational messages without implying success or failure
Characteristics:
- ℹ️ Neutral information
- ℹ️ State updates
- ℹ️ Progress notifications
- ℹ️ Typically logged at Information level
HTTP Status Codes: Usually 200, 202 (Accepted), or custom
Examples:
Msg.System.Processing() // Type: Info, HTTP: 200
Msg.Search.Completed() // Type: Info, HTTP: 200
Msg.System.Queued() // Type: Info, HTTP: 202
Console Output: Blue ℹ
When to Use:
- Long-running operation in progress
- Queue item received
- Background job started
- Status updates
- Non-error notifications
Warning (MessageType.Warning)
Purpose: Alert about potential issues that don’t prevent operation completion
Characteristics:
- Warning: Something needs attention
- Warning: Operation completed but with caveats
- Warning: Potential problem detected
- Warning: Typically logged at Warning level
HTTP Status Codes: Usually 200, 207 (Multi-Status), or 4xx
Examples:
Msg.Crud.NoChangesDetected() // Type: Warning, HTTP: 200
Msg.System.Degraded() // Type: Warning, HTTP: 200
Msg.System.RateLimitExceeded() // Type: Warning, HTTP: 429
Console Output: Yellow ⚠
When to Use:
- Update succeeded but no changes made
- Resource approaching limits
- Deprecated feature used
- Partial success
- Data quality issues
Error (MessageType.Error)
Purpose: Indicate operation failures
Characteristics:
- Operation failed
- Expected error condition
- Recoverable failure
- Typically logged at Error level
HTTP Status Codes: Usually 400-499 (4xx Client Error) or 500-599 (5xx Server Error)
Examples:
Msg.Auth.LoginFailed() // Type: Error, HTTP: 401
Msg.Crud.NotFound("User") // Type: Error, HTTP: 404
Msg.Validation.Failed() // Type: Error, HTTP: 422
Msg.System.Error() // Type: Error, HTTP: 500
Console Output: Red ✗
When to Use:
- Authentication/authorization failed
- Resource not found
- Validation failed
- Business rule violation
- Database error
- External service failure
Critical (MessageType.Critical)
Purpose: Indicate severe system failures requiring immediate attention
Characteristics:
- 🔴 System integrity compromised
- 🔴 Immediate action required
- 🔴 Data corruption possible
- 🔴 Typically logged at Critical level
HTTP Status Codes: Usually 500-599 (5xx Server Error)
Examples:
Msg.Database.ConnectionFailed() // Type: Critical, HTTP: 503
Msg.System.Error() // Type: Critical, HTTP: 500
Msg.System.Unavailable() // Type: Critical, HTTP: 503
Console Output: Red ‼️
When to Use:
- Database unavailable
- Out of memory
- Disk full
- Configuration corruption
- Security breach detected
- Data integrity violated
Message Type Selection Guide
| Scenario | Type | Example |
|---|---|---|
| [✓] User logged in successfully | Success | Msg.Auth.LoginSuccessful() |
| ℹ️ Processing file | Info | Msg.System.Processing() |
| Warning: Update with no changes | Warning | Msg.Crud.NoChangesDetected() |
| [ ] Invalid email format | Error | Msg.Validation.InvalidEmail() |
| 🔴 Database connection failed | Critical | Msg.Database.ConnectionFailed() |
| [✓] Product created | Success | Msg.Crud.Created("Product") |
| ℹ️ Search completed | Info | Msg.Search.Completed() |
| Warning: Validation failed | Warning | Msg.Validation.Failed() |
| [ ] Product not found | Error | Msg.Crud.NotFound("Product") |
| 🔴 Service unavailable | Critical | Msg.System.Unavailable() |
HTTP Status Code Mapping
EasyMessages automatically maps message types to appropriate HTTP status codes:
Success Messages → 2xx
Msg.Crud.Created("User") // HTTP 201 Created
Msg.Crud.Updated("User") // HTTP 200 OK
Msg.Crud.Deleted("User") // HTTP 200 OK (could be 204 No Content)
Msg.Auth.LoginSuccessful() // HTTP 200 OK
Info Messages → 2xx
Msg.System.Processing() // HTTP 202 Accepted
Msg.System.Queued() // HTTP 202 Accepted
Warning Messages → 2xx or 4xx
Msg.Crud.NoChangesDetected() // HTTP 200 OK
Msg.System.RateLimitExceeded() // HTTP 429 Too Many Requests
Error Messages → 4xx or 5xx
Client Errors (4xx):
Msg.Auth.Unauthorized() // HTTP 403 Forbidden
Msg.Crud.NotFound("User") // HTTP 404 Not Found
Msg.Validation.Failed() // HTTP 422 Unprocessable Entity
Msg.Auth.LoginFailed() // HTTP 401 Unauthorized
Server Errors (5xx):
Msg.System.Error() // HTTP 500 Internal Server Error
Msg.Database.ConnectionFailed() // HTTP 500 Internal Server Error
Msg.Network.Timeout() // HTTP 504 Gateway Timeout
Critical Messages → 5xx
Msg.System.Error() // HTTP 500 Internal Server Error
Msg.Database.ConnectionFailed() // HTTP 500 Internal Server Error
Msg.System.Unavailable() // HTTP 503 Service Unavailable
Overriding HTTP Status Codes
// Use the automatic mapping
var notFound = Msg.Crud.NotFound("User");
return StatusCode(notFound.HttpStatusCode ?? 404, notFound.ToJsonObject()); // Returns 404
// Override if needed
var rateLimited = Msg.Auth.LoginFailed().WithStatusCode(429); // Too Many Requests
return StatusCode(rateLimited.HttpStatusCode ?? 429, rateLimited.ToJsonObject());
Message Immutability
Messages are immutable records - once created, they cannot be changed:
// This creates a NEW message, doesn't modify the original
var message1 = Msg.Auth.LoginFailed();
var message2 = message1.WithData(new { UserId = 123 });
// message1 is unchanged
Console.WriteLine(message1.Data == null); // true
// message2 is a new instance with data
Console.WriteLine(message2.Data != null); // true
Benefits:
- [✓] Thread-safe - Can be safely shared across threads
- [✓] Predictable - No side effects
- [✓] Testable - Easy to verify in tests
- [✓] Cacheable - Safe to cache without cloning
Message Categories
EasyMessages organizes messages into logical categories:
Authentication & Authorization (AUTH)
Msg.Auth.LoginFailed()
Msg.Auth.LoginSuccessful()
Msg.Auth.Unauthorized()
Msg.Auth.SessionExpired()
// 10 total messages
CRUD Operations (CRUD)
Msg.Crud.Created("Entity")
Msg.Crud.Updated("Entity")
Msg.Crud.Deleted("Entity")
Msg.Crud.NotFound("Entity")
Msg.Crud.Retrieved("Entity")
// 10 total messages
Validation (VAL)
Msg.Validation.Failed()
Msg.Validation.RequiredField("Field")
Msg.Validation.InvalidFormat("Field")
Msg.Validation.InvalidEmail()
// 15 total messages
System (SYS)
Msg.System.Error()
Msg.System.Processing()
Msg.System.OperationCompleted()
// 10 total messages
Database (DB)
Msg.Database.ConnectionFailed()
Msg.Database.QueryTimeout()
Msg.Database.Deadlock()
// 8 total messages
File Operations (FILE)
Msg.File.UploadSuccessful("document.pdf")
Msg.File.InvalidType("pdf", "docx")
Msg.File.TooLarge("10MB")
// 12 total messages
Network (NET)
Msg.Network.Timeout()
Msg.Network.GatewayTimeout()
// 10 total messages
Total: 100+ built-in messages
See Message Codes Reference for the complete list.
Creating Messages
Using Facades (Recommended)
// Simplest way - use pre-built messages
var message = Msg.Auth.LoginFailed();
With Parameters
// Messages with placeholders
var message = Msg.Crud.Created("User");
// Description: "User has been created successfully."
var message = Msg.Validation.RequiredField("Email");
// Description: "Email is required."
With Data
// Add payload data
var message = Msg.Crud.Created("Product")
.WithData(new
{
Id = 123,
Name = "Widget",
Price = 19.99
});
With Metadata
// Add contextual information
var message = Msg.Auth.LoginFailed()
.WithMetadata("ipAddress", "192.168.1.1")
.WithMetadata("attempt", 3)
.WithMetadata("userAgent", "Mozilla/5.0...");
With Correlation ID
// For distributed tracing
var message = Msg.System.Processing()
.WithCorrelationId("abc-123-def-456");
Chaining Methods
// Chain multiple methods
var message = Msg.Crud.Created("Order")
.WithData(new { OrderId = 789, Total = 99.99 })
.WithMetadata("source", "WebAPI")
.WithMetadata("userId", 123)
.WithCorrelationId(Guid.NewGuid().ToString())
.WithStatusCode(201);
Message Inspection
var message = Msg.Auth.LoginFailed()
.WithData(new { UserId = 123 })
.WithMetadata("attempt", 3);
// Check message type
if (message.Type == MessageType.Error)
{
Console.WriteLine("Operation failed");
}
// Access properties
Console.WriteLine($"Code: {message.Code}");
Console.WriteLine($"Title: {message.Title}");
Console.WriteLine($"Description: {message.Description}");
Console.WriteLine($"Timestamp: {message.Timestamp}");
Console.WriteLine($"HTTP Status: {message.HttpStatusCode}");
// Access data
var data = message.Data as dynamic;
Console.WriteLine($"User ID: {data?.UserId}");
// Access metadata
if (message.Metadata.TryGetValue("attempt", out var attempt))
{
Console.WriteLine($"Attempt: {attempt}");
}
Console Output by Type
Messages display differently in the console based on their type:
// Success (Green ✓)
Msg.Crud.Created("User").ToConsole(useColors: true);
// ✓ User Created
// User has been created successfully.
// [2026-01-09 14:30:00] [CRUD_001]
// Info (Blue ℹ)
Msg.System.Processing().ToConsole(useColors: true);
// ℹ Processing
// Your request is being processed.
// [2026-01-09 14:30:00] [SYS_002]
// Warning (Yellow ⚠)
Msg.Crud.NoChangesDetected().ToConsole(useColors: true);
// ⚠ No Changes Detected
// No changes were detected to update.
// [2026-01-09 14:30:00] [CRUD_009]
// Error (Red ✗)
Msg.Auth.LoginFailed().ToConsole(useColors: true);
// ✗ Authentication Failed
// Invalid username or password.
// [2026-01-09 14:30:00] [AUTH_001]
// Critical (Red ‼️)
Msg.Database.ConnectionFailed().ToConsole(useColors: true);
// ‼️ Database Connection Failed
// Unable to establish database connection.
// [2026-01-09 14:30:00] [DB_001]
Best Practices
[✓] DO:
- Use specific message types - Choose the right type for the situation
- Include relevant data - Add data and metadata for debugging
- Use correlation IDs - Especially in distributed systems
- Let HTTP status codes be automatic - Override only when necessary
- Chain methods for clarity - Build messages fluently
// Good
var notFound = Msg.Crud.NotFound("Product")
.WithMetadata("productId", id)
.WithMetadata("requestedBy", userId)
.WithCorrelationId(correlationId)
.Log(_logger);
return StatusCode(notFound.HttpStatusCode ?? 404, notFound.ToJsonObject());
[ ] DON’T:
- Misuse message types - Don’t use Error for warnings
- Ignore immutability - Remember messages create new instances
- Override HTTP codes unnecessarily - Trust the defaults
- Include sensitive data - Be careful with PII in metadata
- Create messages without context - Add metadata for debugging
// Bad - including password in metadata
var failed = Msg.Auth.LoginFailed()
.WithMetadata("password", password); // Security risk!
return StatusCode(failed.HttpStatusCode ?? 401, failed.ToJsonObject());
// Good
var failed = Msg.Auth.LoginFailed()
.WithMetadata("username", username)
.WithMetadata("ipAddress", ipAddress);
return StatusCode(failed.HttpStatusCode ?? 401, failed.ToJsonObject());
Next Steps
- Message Registry and Stores - Learn how messages are stored and loaded
- Facades (Msg.Auth, Msg.Crud, etc.) - Understand the facade pattern
- Formatters and Outputs - Convert messages to different formats
- Message Codes Reference - Complete list of all messages
Questions? Ask in Discussions