Moving ApplicationUser and other models out of MVC project

后端 未结 1 1747
死守一世寂寞
死守一世寂寞 2020-12-05 08:47

How can I split the properties, functionality and classes out of the default ASP.Net Mvc / Identity 2.0? I am battling with a few things:

  • by default, it wants
相关标签:
1条回答
  • 2020-12-05 09:39

    My solution to this was to: Abstract all the things

    I got around this by abstracting most of the functionality of identity into its own project which allowed for easier unit testing and reuse of the abstraction in other projects.

    I got the idea after reading this article

    Persistence-Ignorant ASP.NET Identity with Patterns

    I then fine tuned the idea to suit my needs. I basically just swapped out everything I needed from asp.net.identity for my custom interfaces which more or less mirrored the functionality provided by the framework but with the advantage of easier abstractions and not 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 mapped results and functionality between my types and the 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 layer is only aware of the abstractions and the implementation is configured at startup. I don't have any using Microsoft.AspNet.Identity at the higher level as they are all using the local abstractions.

    the tiers can look like this :

    • Api - defines interfaces for services (including Identity abstraction interfaces)
    • Domain - stores POCO models representing a business domain
    • Business - stores logic for interacting with domain objects, and consumes services
    • Service - implementation of services, including Entity Framework, and the structure maps for the domain objects
    • Identity - implementation of Microsoft.AspNet.Identity specific services, including Microsoft.AspNet.Identity.EntityFramework; and OWIN configuration
    • Application - in this case, an MVC application.

    In MVC Application layer the AccountController thus only needed

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

    This assumes you are using some DI framework. It is only in the configuring of the IoC that any mention is made of the layer that implements identity completely abstracting it away from those that have need of using identity.

    //NOTE: This is custom code.
    protected override void ConfigureDependencies(IContainerBuilder builder) {
        if (!builder.HasHandler(typeof(IIdentityManager))) {
            builder.PerRequest<IIdentityManager, DefaultUserManager>();
        }
    }
    
    0 讨论(0)
提交回复
热议问题