Home > OS >  What is the difference between using user.Email vs await _userManager.GetEmailAsync(user)?
What is the difference between using user.Email vs await _userManager.GetEmailAsync(user)?

Time:12-28

What is the difference between using user.Email vs await _userManager.GetEmailAsync(user)?

I mean, once I have the user instance itself, what is the use of the _userManager's GetEmailAsync() method which takes exactly that user instance as parameter? I can access the user's email via its property.

I examined the source and I do understand that there is an abstraction layer of using IUserEmailStore but its default implementation is just returning the Email property...

I also do understand, that may exist other implementations, of IUserEmailStore but this case the question will arise: are the user.Email property and _userManager.GetEmailAsync(user) consistent to each other, or are not?

If not, that is a problem, if yes, then we are returned to the original question: what is the use case of using _userManager.GetEmailAsync(user)?

(the same question goes to UserName, PhoneNumber, etc properties)

CodePudding user response:

What is the difference between using user.Email vs await UserManager.GetEmailAsync(user)?

  • user.Email only works if your TUser actually has an Email property in the first place.

    • Fun-fact: ASP.NET-Core-Identity does not actually require whatever class you're using for your TUser to have a String Email property.
      • i.e. what you're presupposing (that users have e-mail addresses) is not actually guaranteed in, nor required by, ASP.NET-Core-Identity.
    • ASP.NET-Core-Identity's only constraint on TUser is TUser : class, so you could even use String or IDictionary for your TUser if you're brave enough.
      • While ASP.NET-Core-Identity does have a String Email { get; } property defined only on class Microsoft.AspNetCore.Identity.IdentityUser<TKey>, but you are not obligated to use this class at all: it's just a prewritten implemention that covers the most common use-cases and (probably) saves most people time by having them subclass it.
  • But there are also other scenarios to consider:

    • ...such as domain-model design where users have multiple e-mail addresses per user, in which case having a single scalar String Email { get; } property simply won't work... though neither would GetEmailAsync either, but that's another part of ASP.NET-Core-Identity's design that you missed: you can implement IUserStore<TUser> and not implement IUserEmailStore<TUser>, so there wouldn't be either an Email property nor a GetEmailAsync method. (Just make sure you don't subclass class UserStoreBase) and instead build your store implementation from scratch.
      • In this hypothetical case, where no types implement IUserEmailStore<TUser>, there wouldn't be any methods anywhere in your codebase that would have to throw NotImplementedException or NotSupportedException. And that's a good thing: a common mantra when designing a domain-model is to "make invalid things impossible" (that's my corruption of the original maxim "make invalid state unrepresentable").
  • Another scenario is some (atypical, I'll admit) system where Users do have an email address, but it's not stored or represented by the in-memory User object, in which case you would have to use a custom implementation of GetEmailAsync to get a user's email address every time.

    • I imagine this might be a possibility when using a back-end user-store with extremely fine-grained security (e.g. some paranoid Active Directory setup where the current Thread's NT security token is used to attest permission to request e-mail addresses from the directory... but that idea is just speculation and I hope no-one ever actually has to support that, at least not without good blood-pressure medication on-hand).

In conclusion: Not every system has user e-mail addresses, and ASP.NET Core Identity doesn't require them to expose them - and the (admittingly very complicated) design of ASP.NET Core Identity reflects that.

  • Related