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;
}
}