实体框架-数据层的IdentityUser



我正在努力设计(或过度设计)我正在做的一个web项目。

我有一个MyProject。数据,。。商业和我的项目。Web DLL .

我的数据层(基于EF6)包含我的实体,db上下文。

我的业务层包含我的存储库(是的,可能不是一个真正的repo模式)。

我已经添加了identityframework到Web项目,当然它创建了ApplicationUser。我已经有一个用户POCO在我的数据层。我想将应用程序用户移到数据层,这样我就可以将其与其他实体结合使用。

要做到这一点的一种方法是有我的数据。用户扩展IdentityUser,也有我的数据。MyContext扩展IdentityDbContext。这导致数据层与asp.net.identity框架强耦合,感觉不太对。

这里的最佳实践是什么?

我不建议让User扩展ApplicationUser。我认为ApplicationUser只是一种方式,用户可以访问您的应用程序(通过登录与电子邮件和通过facebook,谷歌)。您的User实体属于您的域,因此您不需要在那里设置密码(例如)。实际上,单个User可以有许多关联的ApplicationUsers,为什么同一个用户不能用不同的帐户登录?

让你的数据层引用Identity的dll是可以的,你打算在你的项目中多久改变一次?我从来没有见过这种情况发生,一旦你用一个定义好的框架运行一个项目,你就很少改变它,当然你的应用程序可能会增长,但你很少需要改变这样的事情。这样,您的数据层就不会耦合到web项目,而是耦合到库(如前面提到的sunil)。AspNetUser的表将在那里,但不一定是WPF项目需要使用它作为登录方法

此外,我建议你把你的实体保持在业务层(我也鼓励不要在那里使用DataAnnotations),然后让你的数据层映射它们与实体框架使用Fluent API,并封装EF在你的具体存储库中,这应该在数据层只是实现存储库接口从业务层

让你的DBContext扩展IdentityDbContext,但是不要让你的User扩展ApplicationUser,你可以让ApplicationUser有一个User代替。每当一个新的User登录到您的应用程序时,您通常会创建一个新的ApplicationUser,您也可以创建一个User并与之关联。一旦登录,该用户可以将另一个外部登录关联到他的帐户(这意味着多个ApplicationUsers到同一个user)。

下面的代码示例我没有得到任何现有的源代码,我只是为了分析而发明的

业务层-不应该知道其他层,这是最简单的,应该表达你真正的业务,并成为通用语言的一部分

public class User: ITrackable
{
    public int ID { get; protected set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public UserStatus Status { get; set; }
    public DateTime? Birthday { get; set; }
    public virtual ICollection<Address> Addresses { get; protected set; }
    public string LastKnownPlace { get; set; }
    public virtual bool IsPremium()
    {
        // some logic
    }
    public string GetTrackingIdentification()
    {
        // gets some unique key representing this object. Shouldn't be ID, since I might track other objects, soon IDs would dup for different objects...
    }
}
public interface ITrackable
{
    string GetTrackingIdentification();
    string LastKnownPlace { get; set; }
}
public interface ITrackingService<T> where T: ITrackable
{
    void Track(IEnumerable<T> source);
}
public interface IUserTrackingService: ITrackingService<User>
{
    IEnumerable<User> GetDeadbetUsersWithTracking();
}
public interface IUserRepository
{
    IEnumerable<User> GetPremiumUsers();
    IEnumerable<User> GetDeadbets();
}

基础设施层-应该处理如何执行来自应用程序请求的操作。它可以通过实现存储库来使用数据库持久性,或者通过使用实体框架或任何其他提供程序,或者写入文本文件、排队任务、发送电子邮件、日志记录,或者写入注册表,这些都可以称为基础设施服务。这里应该引用业务层,也可以引用Identity的dll。为了保持示例简单,我只实现存储库:

public class YourContext : IdentityDbContext<ApplicationUser>
{
    DbSet<User> DomainUsers { get; set; }
    DbSet<Address> Addresses { get; set; }
    public YourContext(): base("DefaultConnection", throwIfV1Schema: false) { }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<IdentityRole>().Property(r => r.Name).HasMaxLength(200);
        modelBuilder.Entity<ApplicationUser>().Property(a => a.UserName).HasMaxLength(200);
        modelBuilder.Entity<User>().Property(u => u.Name).IsRequired().HasMaxLength(50);
    }
}

服务层-将引用业务层和可能的基础设施层,实现业务服务。服务在这里是一个模棱两可的术语。有应用程序服务、领域服务和基础设施服务。域服务是一个复杂/通用的操作,它是业务逻辑的一部分,但不属于特定的实体。应用服务是一种通过api、WCF等将操作公开给外部世界的方法。基础设施服务,我之前解释过。我将服务层理解为实现业务服务并向应用程序公开的层。由于业务部门不知道服务是如何实现的,因此可以将其委托给外部api。通过这种方式,业务仍然与所有事物解耦。

public class UserTrackingService : IUserTrackingService
{
    private IUserRepository repo;
    // Injects an UserRepository to the service...
    public UserTrackingService(IUserRepository repository)
    {
        this.repo = repository;
    }
    public IEnumerable<User> GetDeadbetUsersWithTracking()
    {
        var users = this.repo.GetDeadbets();
        this.Track(users);
        return users
    }
    public void Track(IEnumerable<User> source)
    {
        // This would use each ITrackable's (in this case each User) Identification to request some external API, get last known place and set to ITrackable's LastKnownPlace property...
        api.Track(source);
    }
}

应用层——可能参考业务层、基础设施/数据层和服务层。这里你应该表达/定义应用程序可以做什么动作,而不是如何做。应用程序只是接收请求,验证请求者并保证他们被授权执行所述操作。一旦一切就绪,它将委托给服务/业务/基础设施层。这里强烈建议使用dto(或viewmodel)来接收数据并向外部世界返回数据。它可能从服务/业务/基础设施层接收域数据,转换为dto并返回。这可以解释为controller .

public class TrackedUserDTO
{
    public string Name { get; set; }
    public string MainAddress { get; set; }
    public string LastKnownPlace { get; set; }
    public decimal TotalDebt { get; set; }
    public bool ShouldBeContacted { get; set; }
}
public class UserController : Controller
{
    private IUserTrackingService service;
    private IUserRepository repository;
    // Injected - IoC
    public UserController(IUserTrackingService service, IUserRepository repository)
    {
        this.service = service;
        this.repository = repository;
    }
    public ActionResult Index()
    {
        return View();
    }
    [Authorize(Roles="Manager,Admin", ErrorMessage="You aren't allowed do see this content...")]
    public ActionResult GetDeadbetUsersWithTracking()
    {
        IEnumerable<User> users = this.service.GetDeadbetUsersWithTracking();
        IEnumerable<TrackedUserDTO> dtoUsers = Mapper.Map<IEnumerable<TrackedUserDTO>>(users);
        return View(dtoUsers);
    }

我强烈推荐阅读这些:

create Domain Services by Philip Brown

Services in domain driven Design by Jimmy Bogard

为什么不在业务层使用dto ?避免贫血域模型(by Martin Fowler)

相关内容

  • 没有找到相关文章

最新更新