My solution for this was: An abstract of all things
I got around this by abstracting most of the functionality of identity in my own project, which made it easier to unit test and reuse abstraction in other projects.
I got an idea after reading this article.
Initial ASP.NET Identity with Templates
Then I tweaked this idea according to my needs. I basically just changed everything I needed from asp.net.identity for my user interfaces, which more or less reflected the functionality provided by the infrastructure, but with the advantage of simpler abstractions rather than implementations.
IIdentityUser
IIdentityManager
IIdentityResult
In my default implementation of the identity manager, which also lives in its own project, I simply wrapped the ApplicationManager and then displayed the results and functions between my types and asp.net.identity types.
public class DefaultUserManager : IIdentityManager { private ApplicationUserManager innerManager; public DefaultUserManager() { this.innerManager = ApplicationUserManager.Instance; }
The application level knows only about abstractions, and the implementation is configured at startup. I don't have using Microsoft.AspNet.Identity at a higher level, since they all use local abstractions.
levels may look like this:
- Api - defines interfaces for services (including identifier abstraction interfaces)
- Domain - saves POCO models representing the business domain.
- Business - stores logic for interacting with domain objects and consumes services
- Service β An implementation of services, including the Entity Framework, and structural maps for domain objects.
- Identity - implementation of Microsoft.AspNet.Identity-specific services, including Microsoft.AspNet.Identity.EntityFramework; and OWIN configuration
- Application - in this case, the MVC application.
In the application layer, the MVC AccountController , therefore, only requires
using MyNamespace.Identity.Abstractions public partial class AccountController : Controller { private readonly IIdentityManager userManager; public AccountController(IIdentityManager userManager) { this.userManager = userManager; } //...other code removed for brevity [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Signin(LoginViewModel model, string returnUrl) { if (ModelState.IsValid) { // authenticate user var user = await userManager.FindAsync(model.UserName, model.Password); if (user != null) { //...code removed for brevity } else { // login failed setFailedLoginIncrementalDelay(); ModelState.AddModelError("", "Invalid user name or password provided."); } } //TODO: Audit failed login // If we got this far, something failed, redisplay form return View(model); } }
It is assumed that you are using some DI framework. Only when IoC is configured does it mention a layer that implements identity, completely abstracting it from those that need to use an identifier.
//NOTE: This is custom code. protected override void ConfigureDependencies(IContainerBuilder builder) { if (!builder.HasHandler(typeof(IIdentityManager))) { builder.PerRequest<IIdentityManager, DefaultUserManager>(); } }