2016-07-30 17 views
6

如何从默认的ASP.Net Mvc/Identity 2.0中分离属性,功能和类?我有几件事情争夺:将ApplicationUser和其他模型移出MVC项目

  • 在默认情况下,它要使用OWIN的背景下,以线了某种依赖注入,并控制经理
  • 它把ApplicationDbContext在应用层面,那里有我体系结构要求它在“较低”级别可用。
  • 它需要我声明与作用于这些属性的功能相同的任何属性(这不适用于我的体系结构)
  • ApplcationUser模型对Asp.Net有依赖关系,我希望打破,如果我到POCO移动到该解决方案的非MVC层

应用架构:

我有了几个层次的解决方案:

  • API - 定义接口的服务
  • 域 - 存储代表业务领域
  • 企业POCO模式 - 专卖店逻辑与域对象进行交互,并消耗服务
  • 服务 - 实施服务,包括实体框架,和的域对象的结构映射
  • 应用程序 - 在这种情况下,是一个MVC应用程序。

我的业务层只知道服务接口,而不是实现,我使用依赖注入来连接所有东西。

我有一些接口定义数据服务的读/写/工作操作单元,以及从DbContext(在我的服务层)继承的这些接口的实现。我不是通过一系列DbSet<MyPoco> MyPocos {get;set;},而是通过传递一系列定义关系的类型配置,然后通过Set<Type>()访问我的类型来连接它。所有这一切都很好。

这个堆栈已经适用于现有的应用程序,并且运行良好。我知道它将转变为一个MVC应用程序,并且只有“开箱即用”的ASP.Net Identity-2存在问题。

回答

7

我对这个解决方案是:摘要所有的东西

我身边这让通过抽象大部分身份的功能集成到自己的项目,该项目允许抽象的其他方便单元测试和重用项目。

我读这篇文章

Persistence-Ignorant ASP.NET Identity with Patterns

然后我微调的思路,以适合我的需要后,计上心来。我基本上只是从asp.net.identity中为我的自定义接口换取了所需的所有内容,这些接口或多或少地反映了框架提供的功能,但具有更容易的抽象而不是实现的优点。

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

在我的身份管理器,它也住在自己的项目的默认实现,我只是包裹ApplicationManager然后映射结果和功能之间的关系ñ我的类型和asp.net.identity类型。

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 
} 

应用程序层只知道抽象,并在启动时配置实现。我没有更高层的using Microsoft.AspNet.Identity,因为他们都使用本地抽象。

该层可以是这样的:

  • API - 定义了服务(包括身份抽象接口)
  • 域接口 - 商店POCO模型代表业务领域
  • 业务 - 存储逻辑对于域对象的交互,以及消费服务
  • 服务 - 实施服务,包括实体框架,结构图,为域对象
  • 身份 - 实施Microsoft.AspNet.Identity特殊服务,包括Microsoft.AspNet.Identity.EntityFramework;和OWIN配置
  • 应用 - 在这种情况下,MVC应用程序。

在MVC应用程序层的AccountController因此只需要

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

这里假设你使用的是一些DI框架。只有在IoC的配置中,任何提到的实现身份的层完全将其从需要使用身份的人身上抽象出来。

//NOTE: This is custom code. 
protected override void ConfigureDependencies(IContainerBuilder builder) { 
    if (!builder.HasHandler(typeof(IIdentityManager))) { 
     builder.PerRequest<IIdentityManager, DefaultUserManager>(); 
    } 
} 
+2

感谢您的详细答复!它看起来会直接下降。你的架构与我的基本相同。我正在使用DI(简单注入器),因此将用户管理器注入控制器应该没问题。 – AndrewP

相关问题