Moving ApplicationUser and other models from an MVC project

How can I separate the properties, functionality and classes from the standard ASP.Net Mvc / Identity 2.0? I struggle with a few things:

  • by default, he wants to use the OWIN context to connect some kind of dependency injection and manage the managers
  • it places ApplicationDbContext at the application level, where my architecture requires it to be available at lower levels.
  • This requires me to declare any properties in the same class as the functions acting on these properties (which do not match my architecture).
  • The ApplcationUser model has Asp.Net dependencies, which I would like to break if I have to move POCO to a non-MVC level solution.

Application Architecture:

I have a solution that has several levels:

  • Api - defines interfaces for services
  • 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.
  • Application - in this case, the MVC application.

My business layer only knows about service interfaces, not implementation, and I use dependency injection to connect everything.

I have some interfaces that define read / write / unit of work operations for a data service and the implementation of these that inherit from DbContext (at my service level). Instead of having a series of DbSet<MyPoco> MyPocos {get;set;} , I connect it by passing a series of type configurations that define relationships and then access my types through Set<Type>() . This all works great.

This stack already exists for an existing application and works well. I know that he will switch to the MVC application, and I have problems with out of the box ASP.Net Identity-2.

+7
architecture asp.net-mvc asp.net-identity-2
source share
1 answer

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

 /// <summary> /// Minimal interface for a user with an id of type <seealso cref="System.String"/> /// </summary> public interface IIdentityUser : IIdentityUser<string> { } /// <summary> /// Minimal interface for a user /// </summary> public interface IIdentityUser<TKey> where TKey : System.IEquatable<TKey> { TKey Id { get; set; } string UserName { get; set; } string Email { get; set; } //...other code removed for brevity } 

IIdentityManager

 /// <summary> /// Exposes user related api which will automatically save changes to the UserStore /// </summary> public interface IIdentityManager : IIdentityManager<IIdentityUser> { } /// <summary> /// Exposes user related api which will automatically save changes to the UserStore /// </summary> public interface IIdentityManager<TUser> : IIdentityManager<TUser, string> where TUser : class, IIdentityUser<string> { } /// <summary> /// Exposes user related api which will automatically save changes to the UserStore /// </summary> public interface IIdentityManager<TUser, TKey> : IDisposable where TUser : class, IIdentityUser<TKey> where TKey : System.IEquatable<TKey> { //...other code removed for brevity } 

IIdentityResult

 /// <summary> /// Represents the minimal result of an identity operation /// </summary> public interface IIdentityResult : System.Collections.Generic.IEnumerable<string> { bool Succeeded { get; } } 

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; } //..other code removed for brevity public async Task<IIdentityResult> ConfirmEmailAsync(string userId, string token) { var result = await innerManager.ConfirmEmailAsync(userId, token); return result.AsIIdentityResult(); } //...other code removed for brevity } 

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>(); } } 
+7
source share

All Articles