# .NET extensions > C# extension methods included in AstrolUI: accent-insensitive search, slugs, money, file sizes, relative time, paging and sorting for EF Core, color contrast and more. Source page: https://doc.astrolui.com/basic-component/extensions Astrol.Entities.Basic: extension methods for text, numbers, dates, AstrolGrid queries, colors, enums and JSON. **Astrol.Entities.Basic** is installed with Astrol.Component.Basic and brings extension methods for what almost every app repeats: cleaning and searching text, showing amounts and dates, paging on the server or picking a readable text color. They all accept **null** and never throw on an empty value. They are plain C#: they work the same in Blazor, an API or a service. ```razor @* Installed with Astrol.Component.Basic (package Astrol.Entities.Basic) *@ @using Astrol.Entities.Basic.Static.Extensions @using Astrol.Entities.Basic.Static @* Auxiliar.NewKey(), Auxiliar.NewDomId() *@ ``` ## 1. Text **ToSearchKey** lowercases the text, removes accents and ñ and leaves a single space between words: compare two keys and search works whether the user types «configuracion» or «CONFIGURACIÓN» (AstrolComboBox uses it this way). **ContainsIgnoreAccents** does it in one call. There are also URL slugs, avatar initials, title-cased names, truncation with «…», email and file-extension validation. Type in the demo to see the result of each method. ```csharp // Search without accents or case (filters, combos, lists) var term = search.ToSearchKey(); // " Árbol " -> "arbol" var result = clients.Where(c => c.Name.ContainsIgnoreAccents(search)); string slug = "¡Hola, Año 2026!".ToSlug(); // "hola-ano-2026" string name = "jUAN pérez".ToTitleCase(); // "Juan Pérez" string avatar = user.FullName.GetInitials(); // "AC" string preview = article.Body.RemoveHtmlTags().Truncate(120); string phone = "5512345678".FormatPhoneNumber(); // "(551) 234 5678" string label = user.Nickname.IfEmpty("(no name)"); bool ok = email.IsValidEmail(); bool allowed = file.Name.IsAllowedExtension(new[] { ".pdf", ".png" }); string tags = product.Tags.JoinText(", "); // skips null / empty ``` ## 2. Numbers, money and sizes **ToMoney** uses the currency format of the current culture (right separators and symbol in es-MX, en-US, es-ES...) and can append the currency code. **ToCompact** shortens large figures for cards and charts. **PercentOf** returns 0 when the total is 0, with no division by zero. **ToFileSize** shows a file size in the right unit. ```csharp string price = 1234.5m.ToMoney(); // "$1,234.50" (current culture) string mxn = 1234.5m.ToMoney("MXN"); // "$1,234.50 MXN" string visits = 3_400_000L.ToCompact(); // "3.4M" (cards and charts) decimal tax = subtotal.ApplyPercent(16); // 16 % of the subtotal decimal progress = done.PercentOf(total); // 0 when total is 0 string size = file.Size.ToFileSize(); // "1.5 MB" long max = 5L.ToBytes(TypeStorage.Megabyte); // 5 242 880 ``` ## 3. Dates **ToRelativeTime** writes «hace 5 minutos» or «5 minutes ago» depending on the app language; a UTC date is compared with UTC time. **ToDisplay** formats dates that may be null (it returns an empty string) and can convert them to local time first. Start and end of day, week and month make range filters simple, and **EndOfDay** includes the whole last day. ```csharp string when = comment.CreatedAt.ToRelativeTime(); // "hace 5 minutos" / "5 minutes ago" string text = order.Date.ToDisplay(); // "24/10/2026 12:00" ("" if null) string local = order.DateUtc.ToDisplay("g", toLocalTime: true); // Date range filters var from = DateTime.Today.StartOfMonth(); var to = DateTime.Today.EndOfDay(); var orders = db.Orders.Where(o => o.Date >= from && o.Date <= to); int age = client.BirthDate.GetAge(); bool weekend = DateTime.Today.IsWeekend(); ``` ## 4. Queries for AstrolGrid For the table in server mode: **SortList** sorts by the column the table asks for (also nested paths such as «Client.Name») by building an expression EF Core translates to SQL; **Paginate** takes the requested page and **ToPaginatedResponse** does all three (sort, count and page) and returns what AstrolGrid expects. **WhereIf** applies a filter only when the user filled it in. With async EF Core, combine SortList and Paginate with CountAsync and ToListAsync. ```csharp // AstrolGrid in server mode: optional filters + sort + count + page private async Task ReadItems(GridResponse request) { var query = db.Clients .WhereIf(onlyActive, c => c.Active) .WhereIf(search.HasValue(), c => c.Name.Contains(search!)); request.AstrolPaginatedResponse = query.ToPaginatedResponse(request.GridInfo); } // Async EF Core: the same steps by hand var sorted = query.SortList(request.GridInfo.SortInfo); // x => x.Name, nested "Client.Name" request.AstrolPaginatedResponse = new() { TotalItems = await query.CountAsync(), PageItems = await sorted.Paginate(request.GridInfo).ToListAsync(), }; ``` ## 5. Colors **GetColorContrast** picks the text color (white or dark, or the ones you pass) with the most contrast on a background, using the WCAG formula: handy for tags or cards with a user-chosen color. **GetContrastRatio** gives the contrast ratio (4.5 is the AA minimum for normal text) and **IsHexColor** / **NormalizeHexColor** validate and normalize what is typed in a color field. ```razor @* Readable text on a color chosen by the user *@ @tag.Name @code { bool valid = input.IsHexColor(); // #rgb, #rrggbb, with or without # string? hex = "FA0".NormalizeHexColor(); // "#ffaa00" double ratio = "#facc15".GetContrastRatio("#222"); // >= 4.5: WCAG AA for text } ``` ## 6. Enums, JSON, collections and copies **GetDisplayName** reads **[Display(Name)]** or **[Description]** from an enum value and **ToSelectList** turns the enum into options for a combo. **DeepClone** makes an independent copy (to edit in a modal and be able to cancel). **ToJson** / **FromJson** use System.Text.Json with the web options, and FromJson returns default when the text is not valid. ```csharp public enum OrderStatus { [Display(Name = "Pending payment")] Pending, [Description("Shipped")] Shipped, Delivered, } string text = order.Status.GetDisplayName(); // "Pending payment" List> options = EnumExtensions.ToSelectList(); // for an AstrolComboBox // Edit a copy in a modal and discard it on Cancel var draft = client.DeepClone(); string json = filters.ToJson(); // camelCase var filters = json.FromJson(); // default if empty or invalid if (items.IsNullOrEmpty()) { /* ... */ } foreach (var item in maybeNull.OrEmpty()) { /* ... */ } string key = Auxiliar.NewKey(32); // random alphanumeric key string id = Auxiliar.NewDomId(); // "aui-k3f9x2" for label for="..." ``` ### Reference **Text** (StringExtensions) - HasValue(), IfEmpty(fallback), Truncate(max, ellipsis) - ToSearchKey(), ContainsIgnoreAccents(term), RemoveDiacritics(keepEnye) - RemoveWhitespace(), CollapseWhitespace(), RemoveHtmlTags() - ToTitleCase(culture), Capitalize(), ToSlug(maxLength), GetInitials(max) - DigitsOnly(), FormatPhoneNumber(), IsValidEmail() - IsAllowedExtension(extensions), JoinText(separator, skipEmpty) - Obfuscate(key) / Deobfuscate(key): the browser storage obfuscation; it is not encryption. **Numbers and sizes** (NumberExtensions, FileSizeExtensions) - PercentOf(total, decimals), ApplyPercent(percent, decimals) - ToMoney(currencyCode, culture, decimals), ToCompact(decimals, culture) - ToFileSize(decimals), ToKilobytes(), ToMegabytes(), ToBytes(TypeStorage) **Dates** (DateExtensions) - ToDisplay(format, toLocalTime, culture) for DateTime, DateTimeOffset and their nullable versions - ToRelativeTime(now, culture) - StartOfDay(), EndOfDay(), StartOfWeek(firstDay), StartOfMonth(), EndOfMonth(), IsWeekend(), GetAge(today) **Queries and collections** (AstrolQueryableExtensions, CollectionExtensions) - SortList(SortInfo | json), Paginate(GridInfo), WhereIf(condition, predicate), ToPaginatedResponse(GridInfo) - IsNullOrEmpty(), HasItems(), OrEmpty(), WhereIf for IEnumerable **Colors, enums, JSON and copies** - GetColorContrast(light, dark), GetContrastRatio(other), IsHexColor(), NormalizeHexColor() - GetDisplayName(), EnumExtensions.ToSelectList() - ToJson(indented), FromJson() - DeepClone() - Auxiliar.NewKey(length), Auxiliar.NewDomId(prefix) The style extensions (GetButtonStyle, GetBoxStyle, GetThemeColor...) are used internally by the components.