title: Allow user to log in with either Email OR UserName (AspNet.Identity)
body: <p>I am wondering if there is a more efficient route to take here.  Using <code>AspNet.Identity</code> I would like to allow the user to sign in to the same text box using either their <code>UserName</code> or <code>Email</code>.  I went ahead and addressed this issue in the <code>AccountController Login ActionResult</code>.  I run the check before calling:</p>
  
  <pre><code>var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: true);
  </code></pre>
  
  <p><em>The Check:</em></p>
  
  <pre><code>//TODO: determine if there is a more efficient way to allow user to login either with Email || UserName
  if (model.UserName.Contains("@"))
  {
      using (var context = new ApplicationDbContext())
      {
          model.UserName = (context.Users.Any(p =&gt; p.Email == model.UserName)) ?
            context.Users.SingleOrDefault(p =&gt; p.Email == model.UserName).UserName :
            model.UserName;
      }
  }
  </code></pre>
  
  <p>My concerns here are two fold:</p>
  
  <ol>
  <li>Is their a more efficient practical way to do this.</li>
  <li>Am I introducing any new security risks or performance risks by doing it this way? </li>
  </ol>
  
  <blockquote>
    <p>I am including the entire <code>ActionResult</code> below for reference.</p>
  </blockquote>
  
  <pre><code>//
  // POST: /Account/Login
  [HttpPost]
  [AllowAnonymous]
  [ValidateAntiForgeryToken]
  public async Task&lt;ActionResult&gt; Login(LoginViewModel model, string returnUrl)
  {
      if (!ModelState.IsValid)
      {
          return View(model);
      }
  
      //TODO: determine if there is a more efficient way to allow user to login either with Email || UserName
      if (model.UserName.Contains("@"))
      {
          using (var context = new ApplicationDbContext())
          {
              model.UserName = (context.Users.Any(p =&gt; p.Email == model.UserName)) ?
                context.Users.SingleOrDefault(p =&gt; p.Email == model.UserName).UserName :
                model.UserName;
          }
      }
  
      // This doesn't count login failures towards account lockout
      // To enable password failures to trigger account lockout, change to shouldLockout: true
      var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: true);
      switch (result)
      {
          case SignInStatus.Success:
              return RedirectToLocal(returnUrl);
          case SignInStatus.LockedOut:
              return View("Lockout");
          case SignInStatus.RequiresVerification:
              return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
          case SignInStatus.Failure:
          default:
              ModelState.AddModelError("", "Invalid login attempt.");
              return View(model);
      }
  }
  </code></pre>
  
  <blockquote>
    <p>related github issue <a href="https://github.com/comeallyouweary/cayw/issues/2" rel="noreferrer">#2</a> and <a href="https://github.com/comeallyouweary/cayw/issues/4" rel="noreferrer">#4</a></p>
  </blockquote>