-
Notifications
You must be signed in to change notification settings - Fork 1
NamingConventions
Arnel Robles edited this page Oct 2, 2026
·
2 revisions
Automatic naming convention conversion, map between snake_case, PascalCase, camelCase, and kebab-case!
using Mapsicle.NamingConventions;
// Source uses snake_case (e.g., from Python API or database)
public class ApiResponse
{
public int user_id { get; set; }
public string first_name { get; set; }
public string email_address { get; set; }
}
// Destination uses PascalCase (C# convention)
public class UserDto
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string EmailAddress { get; set; }
}
// Map with naming convention conversion
var dto = apiResponse.MapWithConvention<ApiResponse, UserDto>(
NamingConvention.SnakeCase,
NamingConvention.PascalCase);
// dto.UserId == apiResponse.user_id
// dto.FirstName == apiResponse.first_name| Convention | Example | C# Property |
|---|---|---|
NamingConvention.PascalCase |
UserName |
Standard C# |
NamingConvention.CamelCase |
userName |
JavaScript/JSON |
NamingConvention.SnakeCase |
user_name |
Python/Ruby/SQL |
NamingConvention.KebabCase |
user-name |
URLs/CSS |
// Convert a single name
var snake = "UserName".ConvertName(NamingConvention.PascalCase, NamingConvention.SnakeCase);
// Result: "user_name"
var pascal = "first_name".ConvertName(NamingConvention.SnakeCase, NamingConvention.PascalCase);
// Result: "FirstName"
var camel = "OrderCount".ConvertName(NamingConvention.PascalCase, NamingConvention.CamelCase);
// Result: "orderCount"// Combine with IMapper for convention-based mapping
var dto = mapper.MapWithConvention<ApiResponse, UserDto>(
apiResponse,
NamingConvention.SnakeCase,
NamingConvention.PascalCase);The convention pass skips a member the mapper binds, or the configuration ignores or resolves with
MapFrom. Any other member is filled while it still holds the value a new UserDto starts with, so
what an AfterMap set is kept. A member initialised to a new instance, such as Tags = new(), is
always filled, because every destination starts with a different instance.
// Check if names match across conventions
bool match = NamingConvention.NamesMatch(
"user_name", NamingConvention.SnakeCase,
"UserName", NamingConvention.PascalCase);
// Result: trueMatching compares the letters and digits and ignores case and where the words break, so user_id
matches UserID and address_line_1 matches AddressLine1. When a name is converted, an acronym
stays one word: HTTPServerID becomes http_server_id.
public class ExternalApiClient
{
private readonly HttpClient _http;
public async Task<UserDto> GetUserAsync(int id)
{
// External API returns snake_case JSON
var response = await _http.GetFromJsonAsync<ExternalUserResponse>($"/users/{id}");
// Convert to C# conventions
return response.MapWithConvention<ExternalUserResponse, UserDto>(
NamingConvention.SnakeCase,
NamingConvention.PascalCase);
}
}
// External API response (snake_case)
public class ExternalUserResponse
{
public int user_id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email_address { get; set; }
public DateTime created_at { get; set; }
}
// Internal DTO (PascalCase)
public class UserDto
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public DateTime CreatedAt { get; set; }
}Mapsicle
Packages
- Core
- Fluent
- EntityFramework
- Validation
- NamingConventions
- Serilog
- Dapper
- AspNetCore
- Json
- Caching
- Audit
- DataAnnotations
Reference