数据层中的IdentityUser [英] IdentityUser in Data layer

查看:138
本文介绍了数据层中的IdentityUser的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为自己正在做的Web项目设计(或过度设计)。

I am struggling with my design (or over-design) of a web project I am doing.

我有一个MyProject.Data,MyProject.Business和

I have a MyProject.Data, MyProject.Business, and MyProject.Web DLL's.

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

My data layer (EF6 based) contains my entities, db context.

我的业务层包含我的存储库(是的,也许不是真正的回购模式)。

My business layer contains my repositories (yeah maybe not a true repo pattern).

我已经将IdentityFramwork添加到Web项目中,并且它创建了ApplicationUser。我的数据层中已经有一个用户POCO。我想将应用程序用户移到数据层,以便可以将其与其他实体结合使用。

I have added IdentityFramwork to the Web Project, and of cource it creates ApplicationUser. I already have a User POCO in my Data layer. I would like to move the Application user into the Data layer, so I can use it in conjunction with other entities.

一种方法是让我的Data.User扩展IdentityUser,也让我的Data.MyContext扩展IdentityDbContext。这导致数据层与感觉不太正确的asp.net.identity框架紧密耦合。

One way to do this is have my Data.User extend IdentityUser, and also have my Data.MyContext extend IdentityDbContext. This results in the Data layer being strongly coupled to the asp.net.identity framework which doesn't quite feel right.

这里的最佳实践是什么?

What is the best practise here?

推荐答案

我不建议让 User 扩展 ApplicationUser 。我认为 ApplicationUser 只是用户访问您的应用程序的一种方式(通过电子邮件登录并通过Facebook,google传递)。您的用户实体属于您的域,因此您在此不需要密码(例如)。实际上,一个 User 可能有许多关联的ApplicationUser,为什么同一用户不能使用不同的帐户登录?

I would not recommend making User extends ApplicationUser. I consider ApplicationUser just a way an user can access your application (through login with email and pass, through facebook, google). Your User entity belongs to your domain, thus you don't need password there (as an example). Actually, a single User could have many ApplicationUsers associated, why couldn't the same user login with differente accounts?

可以让您的数据层引用Identity的dll,您打算在项目中多久更改一次?我真诚地从未见过这种情况,一旦将项目运行在已定义的框架中,就很少更改它,当然您的应用程序可能会增长,但是您几乎不需要更改此类内容。这样,您的数据层不会耦合到Web项目,而是耦合到库(例如提到的 sunil )。 AspNetUser的表将在那里,但不是必须的,WPF项目需要使用它作为登录方法

It's ok to make your Data Layer references Identity's dlls, how often are you going to change this in your project? I sincerely have never seen this happens, once you put a project to run with a defined framework, you rarely change it, of course your application might grow, but you rarely need to change things like this. This way, your Data Layer is not coupled to a web project, but to a library (like sunil mentioned). AspNetUser's tables will be there, but not necessarilly a WPF project need to use it as a login method

此外,我建议您将实体保留在 Business中图层(我也建议不要在那里使用 DataAnnotations ),然后使数据层实体框架使用Fluent API,并将EF封装在您的具体存储库中,该存储库应位于数据层中,只需从业务层实现存储库接口即可。

Furthermore, I suggest you to keep your entities in the Business Layer (I also encourage not to use DataAnnotations there), then make your Data Layer map them with Entity Framework using Fluent API, and encapsulate EF inside your Concrete Repositories, which should be in Data Layer just implementing Repositories interfaces from Business Layer.

使您的DBContext扩展IdentityDbContext,但不要让您的用户扩展ApplicationUser,您可以使ApplicationUser拥有一个User。每当有新用户登录到您的应用程序时,通常您会在该位置创建新的ApplicationUser,也可以创建 User 并与其关联。登录后,该用户可以将另一个外部登录名与其帐户关联(这意味着许多ApplicationUser都与同一用户)。

Make your DBContext extends IdentityDbContext, but don't make your User extends ApplicationUser, you could make an ApplicationUser has an User instead. Whenever a new User logs in your application, where you would normally create a new ApplicationUser, you could also create an User and associate with it. Once logged, this user could associate another external logins to his account (which means many ApplicationUsers to the same User).


下面的代码示例I没有找到任何现有资源,我只是发明分析用

Code Sample below I didn't get for any existing source, I've just invented for analysis

业务层-不应该知道其他层,这是最简单的方法,应该表达您的真实业务并成为普适语言的一部分

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

基础结构层-应处理应从应用程序请求的操作执行。它可能通过实现存储库(使用Entity Framework或任何其他提供程序)来使用数据库持久性,或者写入文本文件,排队任务,发送电子邮件,记录日志,也许写入注册表,这些可以称为Infra Services。在这里,您应该引用业务层,也可以引用Identity的dll。为了使示例简单,我仅实现存储库:

Infrastructure Layer - should deal with how actions requested from applications should be executed. It could be using database persistence by implementing repositories, either by using Entity Framework or any other provider, or writting to text files, queuing tasks, sending e-mails, logging, maybe writting to registry, these can be known as Infra Services. Here you should reference Business layer and you could reference Identity's dlls as well. To keep example simple, I'm just implementing repositories:

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

}

服务层-将有关实施业务服务的信息,请参考Businness以及Infra层。这里的服务是一个模糊的术语。有应用程序服务,域服务和基础设施服务。 域服务是一种复杂/通用操作,属于业务逻辑,但不属于特定实体。应用服务是通过API,WCF等将动作暴露给外部世界的一种方式。我将服务层理解为实现业务服务并向应用程序公开的层。由于企业不知道服务的实现方式,因此可以委托给外部API。这样,业务仍与一切脱钩。

Service Layer - Will reference Businness and maybe Infra layers, implementing Business Services. Service is an ambiguous term here. There are Application Services, Domain Services and Infra Services. A Domain Service is a complex/generic operation which is part of the business logic, but does not belong to specific entities. Application Service is a way to expose actions to external worlds via APIs, WCF, etc. Infra services I explained before. I understand a Service Layer as a Layer which implements Business Services and exposes to Applications. Since Business does not know how services are implemented, it's ok to delegate to external APIs, for example. That way, business is still decoupled from everything.

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(或ViewModels)来接收数据并将其返回给外部世界。它可能会从服务/业务/基础层接收域数据,转换为DTO并返回。可以解释为控制器。

Application Layer - might reference Business, Infra/Data and Service Layers. Here you should express/defined what actions an app can do, but not how. Apps just receive requests, authenticates the requester and guarantees they are authorized to perform said action. Once everything is ok, it delegates either to a service/business/infra layers. Here is strongly recommended to use DTOs (or ViewModels) to receive and return data to external world. It might receives domain data from service/business/infra layers, translates to DTOs and return. This can be interpreted as the Controllers.

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

我强烈建议阅读以下内容:

I strongly recommend reading these:

通过Philip Brown创建域服务

Jimmy Bogard提供的域驱动设计服务

为什么不在业务层内部使用DTO?为了避免贫血域模型(由Martin Fowler撰写)

Why not use DTOs inside business layer? To avoid Anemic Domain Model (by Martin Fowler)

这篇关于数据层中的IdentityUser的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆