Show a name and profile photo with .NET and Gravatar 今

Most systems dealing with users have some way of letting people input their name and upload a profile photo. Other systems only know user's email addresses and don't have the luxury of showing additional information. Don't have a profile photo on your users or do you want a fallback photo before the user decides to upload one? In this post, I'll show you how to use Gravatar to achieve both.

So, what is Gravatar? Gravatar is short for Globally Recognized Avatar. It's a service provided by WordPress (they bought it some years ago if I remember correctly) which means that all WordPress accounts also have a Gravatar account. Gravatar will let you pull information registered on your WordPress/Gravatar account through a simple email-based API. This means that you will be able to show a profile photo and a name for a lot of users based on their email only.

Let me stop talking about what Gravatar can do and show you some code. I'll start by demonstrating the most simple way to get a Gravatar profile photo which is through an URL request. Then move on to call their API from C#.

Consider an ASP.NET Core application with a user profile page. You know the user's email and nothing more. To include a profile photo without having to implement any upload feature and static storage, simply include an img element on the profile page with an URL on the following form:

<img src="https://www.gravatar.com/avatar/HASH" />

You will need to replace HASH with an MD5 hash of the user's email. If you want to show a static profile image of yourself on your blog or similar, you can use this MD5 Encoder to create an MD5 hash from your email. For dynamic generation, I usually have the following extension method included in all of my projects anyway:

public static class StringExtensions
{
    public static string ToMd5(this string s)
    {
        if (string.IsNullOrWhiteSpace(s)) return string.Empty;

        var loweredBytes = Encoding.Default.GetBytes(s.ToLower());
        var buffer = new MD5CryptoServiceProvider().ComputeHash(loweredBytes);
        var sb = new StringBuilder(buffer.Length * 2);
        for (var i = 0; i < buffer.Length; i++)
        {
            sb.Append(buffer[i].ToString("X2"));
        }

        return sb.ToString().ToLower();
    }
}

I should probably credit someone for writing this code, but unfortunately, I don't remember where I copy/pasted it from. Probably StackOverflow

Continuing the example for ASP.NET Core, including the profile photo on the profile page can use the Username property on the model:

<img src="https://www.gravatar.com/avatar/@Model.Username.ToMd5()" />

The profile page shows a nice avatar:

This happens because I have an active Gravatar account with that email. If no Gravatar account is found from the email hash, a generic image is shown:

A range of options for generating unique images for non-existing emails exist. Like generating cute robots:

<img src="https://www.gravatar.com/avatar/@Model.Username.ToMd5()?d=robohash" />

I simply added ?d=robohash to the URL which generates this:

That's a quick tour of generating profile photos from an email address directly in the Razor (or HTML) file. But what if you want to fetch these data on the server to include in an HTTP response or to store the Gravatar result in a database? Luckily, Gravatar has a nice API as well. First, we need some model classes representing the JSON returned from Gravatar:

private class Response
{
    public Entry[] entry { get; set; }
}

private class Entry
{
    public Name name { get; set; }

    public Photo[] photos { get; set; }

    public string displayName { get; set; }
}

private class Name
{
    public string formatted { get; set; }
}

private class Photo
{
    public string value { get; set; }

    public string type { get; set; }
}

I won't go into details around the Gravatar response, but as you see, we get an array of entries back from the API with a name and zero or more profile photos.

To call Gravatar, I'll create a wrapper of a HttpClient to request and map the result to the model:

public class GravatarApi
{
    private HttpClient httpClient;

    public GravatarApi(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }

    public async Task<(string, string)> GetProfile(string email)
    {
        var response = await httpClient.GetFromJsonAsync<Response>($"{email.ToMd5()}.json");
        var entry = response.entry.FirstOrDefault();
        if (entry == null) return ("", "");
        var name = entry?.name.formatted ?? (entry.displayName ?? "");
        var photo = entry.photos != null && entry.photos.Any() && !string.IsNullOrWhiteSpace(entry.photos.First().value) ? entry.photos.First().value : "";
        return (name, photo);
    }
}

The GravatarApi class accept a HttpClient in its constructor and profile a GetProfile method to fetch a name and profile photo from an email. I'm using a Tuple for the return type but this can easily be changed to a strongly typed object if you prefer.

Initializing the GravatarApi class can be done in the ConfigureServices method in the Startup.cs file in ASP.NET Core:

services.AddHttpClient<GravatarApi>(x =>
{
    x.BaseAddress = new Uri("https://en.gravatar.com/");
    x.DefaultRequestHeaders.UserAgent.ParseAdd("MyTestApp/1.0");
});

Gravatar requires a user agent in all requests why I simply put in a test string. You will need to input something that makes sense in your context to avoid errors from the Gravatar API.

Injecting and calling GravatarApi in a Razor page or MVC controller is easy:

public class IndexModel : PageModel
{
    private readonly GravatarApi gravatarApi;

    public string Name { get; private set; }
    public string Photo { get; private set; }

    public IndexModel(GravatarApi gravatarApi)
    {
        this.gravatarApi = gravatarApi;
    }

    public async Task OnGet()
    {
        var result = await gravatarApi.GetProfile("EMAIL_GOES_HERE");
        Name = rr.Item1;
        Photo = rr.Item2;
    }
}

elmah.io: Error logging and Uptime Monitoring for your web apps

This blog post is brought to you by elmah.io. elmah.io is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With elmah.io, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.

See how we can help you monitor your website for crashes Monitor your website