ASP.NET IdentityUserを他のエンティティから分離する


11

私が持っているProjectName.Coreすべての私のビジネスロジックと私のエンティティとその行動を含むライブラリを。現在、Entity Frameworkやその他のDALとはまったく関係がありません。これらのことを分離しておくのが好きだからです。Entity Framework構成(Fluent APIを使用)はProjectName.Infrastructureプロジェクトに常駐するため、エンティティをEFにプッシュできます。基本的には、オニオンのようなアーキテクチャの方向に向かっています。

ただし、ASP.NET Identityフレームワークをミックスに追加する場合、ApplicationUserエンティティをIdentityUserクラスから継承する必要がありますが、ApplicationUserクラスには他のエンティティとの関係があります。継承するIdentityUser際に、エンティティプロジェクトにエンティティフレームワークへの参照を導入しています。これは、そうしたくない1つの場所です。(Entity FrameworkベースのIDシステムを使用しているため)ApplicationUserエンティティプロジェクトからプロジェクトにクラスをプルするとInfrastructure、循環参照が発生するため、どちらにすることもできません。

これを回避する方法はありますか?ASP.NET Identityを使用しないことに加えて、2つの層の間のきれいな分離を保つことができますか?


1
コアプロジェクトでIApplicationUserインターフェイスを作成し、インフラストラクチャで実装を維持することはできませんか?私の意見では、APIを作成する場合、または実行時にインターフェイスの実装を交換する必要がある場合を除き、すべての非UIコードを1つのプロジェクトに保持します。多数の異なるプロジェクトがあると、精神的およびコード管理のオーバーヘッドが増加するだけで、大きなメリットはありません。
モルタラペマン

回答:


12

コアライブラリでASP.NET Identityとは関係のないUserクラスを作成できます。

public class User {
    public Guid UserId { get; set; }
    public string UserName { get; set; }
    public string EmailAddress { get; set; }
    public string EmailAddressConfirmed { get; set; }
    public string PhoneNumber { get; set; }
    public string PhoneNumberConfirmed { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }

    ...

    public virtual ICollection<Role> Roles { get; set; }
    public virtual ICollection<UserClaim> UserClaims { get; set; }
    public virtual ICollection<UserLogin> UserLogins { get; set; }
}

Entity Frameworkを使用している場合は、エンティティの構成クラスを作成します(オプション)。

internal class UserConfiguration : EntityTypeConfiguration<User>
{
    internal UserConfiguration()
    {
        ToTable("User");

        HasKey(x => x.UserId)
            .Property(x => x.UserId)
            .HasColumnName("UserId")
            .HasColumnType("uniqueidentifier")
            .IsRequired();

        Property(x => x.PasswordHash)
            .HasColumnName("PasswordHash")
            .HasColumnType("nvarchar")
            .IsMaxLength()
            .IsOptional();

        Property(x => x.SecurityStamp)
            .HasColumnName("SecurityStamp")
            .HasColumnType("nvarchar")
            .IsMaxLength()
            .IsOptional();

        Property(x => x.UserName)
            .HasColumnName("UserName")
            .HasColumnType("nvarchar")
            .HasMaxLength(256)
            .IsRequired();

        // EmailAddress, PhoneNumber, ...

        HasMany(x => x.Roles)
            .WithMany(x => x.Users)
            .Map(x =>
            {
                x.ToTable("UserRole");
                x.MapLeftKey("UserId");
                x.MapRightKey("RoleId");
            });

        HasMany(x => x.UserClaims)
            .WithRequired(x => x.User)
            .HasForeignKey(x => x.UserId);

        HasMany(x => x.UserLogins)
            .WithRequired(x => x.User)
            .HasForeignKey(x => x.UserId);
    }
}

Role、UserClaim、およびUserLoginのクラスも作成する必要があります。上記の名前が気に入らない場合は、好きな名前を付けることができます。

Webレイヤーで、AppUser(または選択した場合は別の名前)というクラスを作成します。このクラスは、ASP.NETアイデンティティ実装する必要たIUser <処理鍵>インターフェイス、処理鍵は、(プライマリ・キーのデータ型でのGuid上記例では)。

public class AppUser : IUser<Guid>
{
    public AppUser()
    {
        this.Id = Guid.NewGuid();
    }

    public AppUser(string userName)
        : this()
    {
        this.UserName = userName;
    }

    public Guid Id { get; set; }
    public string UserName { get; set; }
    public string EmailAddress { get; set; }
    public string EmailAddressConfirmed { get; set; }
    public string PhoneNumber { get; set; }
    public string PhoneNumberConfirmed { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }
}

Webプロジェクト内のUserManagerへのすべての参照をUserManager <AppUser、Guid>に変更します。

最後に、独自のUserStoreを作成します。基本的に、カスタムUserStoreはAppUserオブジェクトを取得し、それをUserエンティティオブジェクトに変換してから永続化します。これらのメソッドの1つの例を以下に示します。

public class UserStore : 
    IUserLoginStore<AppUser, Guid>, 
    IUserClaimStore<AppUser, Guid>, 
    IUserRoleStore<AppUser, Guid>, 
    IUserPasswordStore<AppUser, Guid>, 
    IUserSecurityStampStore<AppUser, Guid>, 
    IUserStore<AppUser, Guid>, 
    IDisposable
{
    private User MapFromAppUser(AppUser appUser)
    {
        if (appUser == null)
            return null;

        var userEntity = new User();

        PopulateUser(userEntity, appUser);

        return userEntity;
    }

    private void PopulateUser(User user, AppUser appUser)
    {
        user.UserId = appUser.Id;
        user.UserName = appUser.UserName;
        user.EmailAddress = appUser.EmailAddress;
        user.EmailAddressConfirmed = appUser.EmailAddressConfirmed;
        user.PhoneNumber = appUser.PhoneNumber;
        user.PhoneNumberConfirmed = appUser.PhoneNumberConfirmed;
        user.PasswordHash = appUser.PasswordHash;
        user.SecurityStamp = appUser.SecurityStamp;

        // First name, last name, ... 
    }

    #region IUserStore<AppUser, Guid> Members

    public Task CreateAsync(AppUser appUser)
    {
        if (appUser == null)
            throw new ArgumentNullException("appUser");

        var userEntity = MapFromAppUser(appUser);

        // Persist the user entity to database using a data repository.
        // I'll leave this to you.
    }

    ...

    #endregion
}

可能な実装の完全な説明を取得するには、ここをクリックしてください

最後に、それはあなたの選択です。CoreライブラリでIdentityフレームワークを参照するだけでなく、この実装を維持するのにかかる労力を測定します。個人的には、上記で説明した方法で実行することを考えましたが、ASP.NET Identityフレームワークが更新されるたびにコードを変更しなければならない可能性があるため、そうしませんでした。

うまくいけば、これがあなたの質問を助けて答えてくれることを願っています!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.