What to do when emojis are not rendered correctly by ASP.NET Core web applications

For better or worse emojis have become part of our everyday life, we use them to communicate our emotions and as a quick way to acknowledge our approval or disapproval as the case may be! ūüĎć

Recently I came across what seemed to be a rather odd issue where an emoji was being used within an account name and said emoji was not being rendered correctly by an ASP.NET Core web application ūü§Ē

In this article, I want to share a quick tip with you regarding the cause of the issue and how you can leverage specific .NET class libraries to work around this kind of problem ‚úÖ

The issue

Ok, enough with all the emojis already, let’s get down to the nitty-gritty.

When an emoji (or any other character for that matter) fails to render on a web page, you’ll usually see a question mark symbol displayed in its place, as follows.

ÔŅĹ

The above symbol could be displayed for several reasons. For example, it could be that the character you are trying to display isn’t part of the character set that is currently in use (the HTML5 specification recommends the UTF-8 character set).

However, the specific issue that I came across was happening due to code that was using the first character within a string as the initial to display within a web component.

Let’s dive into an example that simulates the issue in the following section.

Example specifics

Suppose that we want to display a basic profile placeholder somewhere on our page that renders the first initial of the current user’s name to indicate who is logged in.

A very simple version of this could be implemented in an ASP.NET Core Razor Page as follows.

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}
 
<div class="profile-placeholder">
    @Model.UserNameInitial
</div>

@Model.UserNameInitial will render the initial character of the user’s name and is wrapped with a div element that has a ‘profile-placeholder’ CSS class.

For demonstration purposes, the CSS for the ‘profile-placeholder’ class is defined as follows.

.profile-placeholder {
    width: 60px;
    height: 60px;
    color: #404040;
    border: 5px solid #404040;
    border-radius: 50%;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 36px;
    font-weight: bold;
}

Note that I’m using precise pixel values for demonstration purposes. In a production application, you’ll likely consider using alternative size/length units.

The above CSS defines a grey circular border with a slight box shadow and centred contents. When the UserNameInitial property has been set to a valid character, such as ‘J’, the output will look as follows.

Profile placeholder with initial
Profile placeholder with initial

When implementing the logic that gets the initial from the user’s name, you might be tempted to write code that is similar to the following since only one character needs to be displayed to represent the initial.

public class IndexModel : PageModel
{
    public char UserNameInitial { get; set; } = ' ';
 
    public void OnGet()
    {
¬†¬†¬†¬†¬†¬†¬†¬†string¬†userName¬†=¬†User.Identity?.Name¬†??¬†"ūüĎĹ";
 
        if (userName.Length > 0 )
        {
            UserNameInitial = userName[0];
        }
    }
}

In the above code, UserNameInitial is the property that is used for data binding on the Razor view. The property has been defined as a char type, which represents a single Unicode UTF-16 character.

Within the OnGet method that is called when a GET request is made for the Index page, the userName variable is set based on the current user’s name. If the name is null then we don’t know who the user is, so we set the user’s name to an alien emoji for kicks. If the length of the user’s name is greater than zero, the UserNameInitial property value is set to the first character from the userName variable.

The problem with the above approach is that instead of the alien emoji, we see an invalid character.

Profile placeholder with invalid character
Profile placeholder with invalid character

This is happening because an emoji is made up of two code units and therefore takes up two characters within the string instead of one.

We could work around this by calling Substring(0, 2) or [..2] on the string to take the first two characters, but how would we know when to take two characters instead of one?

Solution

As it turns out, we can use the StringInfo.GetNextTextElement method to get a text element at a specific index within a string. In our case, we always want the first text element, so that means we can simply specify 0 as the index.

Here’s how we would update the code to work correctly.

public class IndexModel : PageModel
{
    public string UserNameInitial { get; set; } = "";
 
    public void OnGet()
    {
¬†¬†¬†¬†¬†¬†¬†¬†string¬†username¬†=¬†User.Identity?.Name¬†??¬†"ūüĎĹ";
 
if (userName.Length > 0 )
{
UserNameInitial = StringInfo.GetNextTextElement(username, 0);
}     } }

The UserNameInitial property is now a string instead of a char type and we’re calling the GetNextTextElement method. With these changes in place, the emoji is now rendered correctly, as shown in the following screenshot.

Profile placeholder with emoji
Profile placeholder with emoji

The GetNextTextElement method provides us with a reliable way of getting a text element at a specific index within a string, regardless of how many code units make up the character.

By the way, the StringInfo class contains several other helpful static methods that include the following.

If you have a problem that is a bit more complex, you can use one or more of the above methods to give you more control to extract and manipulate text elements in a string.

Lastly, if you’re working with emojis, Emojipedia is a great resource for searching for and copying emojis.

Summary

In this post, I have provided a quick tip regarding how to handle emojis correctly in an ASP.NET Core web application.

I briefly discussed a recent problem I was facing with rendering emojis, then walked through a simple example of the problem occurring, and finally looked at what can be done to resolve the problem by using StringInfo class methods.

Of course, there is a lot more detail that we could go into regarding strings, character sets, etc. However, I hope that by making you aware of the methods provided by the StringInfo class you will be able to find a suitable solution to your specific problem ūüėé


I hope you enjoyed this post! Comments are always welcome and I respond to all questions.

If you like my content and it helped you out, please check out the button below ūüôā

Comments