EF Database First MVC5를 사용한 ASP.NET ID


88

Database First 및 EDMX와 함께 새로운 Asp.net Identity를 사용할 수 있습니까? 아니면 코드를 먼저 사용합니까?

내가 한 일은 다음과 같습니다.

1) 새 MVC5 프로젝트를 만들고 새 ID로 데이터베이스에 새 사용자 및 역할 테이블을 만들도록했습니다.

2) 그런 다음 Database First EDMX 파일을 열고 관련된 다른 테이블이 있으므로 새 Identity Users 테이블로 끌어 왔습니다.

3) EDMX를 저장하면 Database First POCO 생성기가 자동으로 User 클래스를 생성합니다. 그러나 UserManager 및 RoleManager는 새 Identity 네임 스페이스 (Microsoft.AspNet.Identity.IUser)에서 상속 된 User 클래스를 예상하므로 POCO User 클래스를 사용할 수 없습니다.

가능한 해결책은 내 사용자 클래스가 IUser에서 상속되도록 POCO 생성 클래스를 편집하는 것입니다.

아니면 ASP.NET Identity는 Code First Design 과만 호환됩니까?

++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++

업데이트 : 아래의 Anders Abel의 제안에 따라 이것이 제가 한 일입니다. 작동하지만 더 우아한 솔루션이 있는지 궁금합니다.

1) 자동 생성 엔터티와 동일한 네임 스페이스 내에 부분 클래스를 만들어 엔터티 User 클래스를 확장했습니다.

namespace MVC5.DBFirst.Entity
{
    public partial class AspNetUser : IdentityUser
    {
    }
}

2) DBContext 대신 IdentityDBContext에서 상속하도록 DataContext를 변경했습니다. EDMX를 업데이트하고 DBContext 및 Entity 클래스를 다시 생성 할 때마다이 값을 다시 설정해야합니다.

 public partial class MVC5Test_DBEntities : IdentityDbContext<AspNetUser>  //DbContext

3) 자동 생성 된 사용자 엔터티 클래스 내에서 다음 4 개 필드에 재정의 키워드를 추가하거나 이러한 필드가 IdentityUser (1 단계)에서 상속되므로 주석 처리해야합니다. EDMX를 업데이트하고 DBContext 및 Entity 클래스를 다시 생성 할 때마다이 값을 다시 설정해야합니다.

    override public string Id { get; set; }
    override public string UserName { get; set; }
    override public string PasswordHash { get; set; }
    override public string SecurityStamp { get; set; }

1
구현의 샘플 코드가 있습니까? 위의 내용을 복제하려고하면 로그인하거나 사용자를 등록하려고 할 때 오류가 발생합니다. "AspNetUser는 현재 컨텍스트에 대한 모델의 일부가 아닙니다."여기서 AspNetUser는 내 사용자 엔티티입니다
Tim

AspNetUser 테이블을 EDMX에 추가 했습니까? 또한 AccountController가 ApplicationContext가 아닌 MVC5Test_DBEntities (또는 DB 컨텍스트 이름이 무엇이든)를 사용하고 있는지 확인하십시오.
Patrick Tran

8
ASP.NET Identity는 ____의 무더기입니다. 데이터베이스 우선에 대한 끔찍한 지원, 문서 없음, 잘못된 참조 제한 (SQL 서버에서 ON CASCADE DELETE 누락) 및 ID에 문자열 사용 (성능 문제 및 인덱스 조각화). 그리고 이것은 아이덴티티 프레임 워크에서의 297 번째 시도입니다 ...
DeepSpace101

1
@ DeepSpace101 Identity는 Code-first와 동일하게 DB-first를 지원합니다. 템플릿은 코드 우선으로 설정되어 있으므로 템플릿에서 시작하는 경우 몇 가지 사항을 변경해야합니다. 계단식 삭제는 잘 작동하며 문자열을 쉽게 int로 변경할 수 있습니다. 아래 내 대답을 참조하십시오.
Shoe

1
@Shoe 나는 당신이 틀릴 수 있다고 생각합니다. db-first (문서 없음)에서 이것을 구현하는 방법에 대한 작동하고 포괄적 인 예제 / 튜토리얼을 아직 찾지 못했습니다. API는 IdentityUser.Roles 속성을 통해 접합 테이블 "IdentityUserRoles"를 참조하려고합니다.이 속성은 접합 테이블이 엔터티로 노출되지 않기 때문에 EF db-first에서 관계를 끊습니다 (불량한 참조 제약 조건). 상속 된 클래스에서 유형 매개 변수를 지정하여 사용자 정의 할 수 있기 때문에 ID의 문자열에 대해 동의하지 않습니다. 요약하자면, 그들이 DB를 먼저 염두에 두지 않은 것처럼 보입니다.
Lopsided

답변:


16

POCO 및 Database First와 함께 ID 시스템을 사용할 수 있어야하지만 몇 가지 조정이 필요합니다.

  1. 엔티티 클래스를 만들기 위해 POCO 생성을 위해 .tt- 파일을 업데이트합니다 partial. 이렇게하면 별도의 파일에 추가 구현을 제공 할 수 있습니다.
  2. User다른 파일 에서 클래스 의 부분 구현 만들기

 

partial User : IUser
{
}

그러면 User실제 생성 된 파일을 건드리지 않고 클래스가 올바른 인터페이스를 구현 하게됩니다 (생성 된 파일을 편집하는 것은 항상 나쁜 생각입니다).


감사. 나는 이것을 시도하고 그것이 잘되면보고해야 할 것입니다.
Patrick Tran

나는 당신이 언급 한 것을 시도했습니다. 업데이트 된 정보에 대한 내 게시물을 참조하십시오 ... 그러나 솔루션은 그다지 우아하지 않았습니다. : /
Patrick Tran

나는 똑같은 문제를 겪고 있습니다. DB 우선에 대한 문서는 매우 드문 것 같습니다. 이것은 좋은 제안하지만 난 당신에게 맞아요 생각, 꽤 작동하지 않습니다

4
아직 해킹이 아닌 해결책이 있습니까?
user20358 2014

Onion Architecture를 사용하고 있으며 모든 POCO가 Core에 있습니다. IUser를 사용하지 않는 것이 좋습니다. 그래서 다른 해결책이 있습니까?
Usman Khalid

13

내 단계는 매우 비슷하지만 공유하고 싶었습니다.

1) 새 MVC5 프로젝트 만들기

2) 새 Model.edmx를 만듭니다. 새 데이터베이스이고 테이블이없는 경우에도 마찬가지입니다.

3) web.config를 편집하고 생성 된 연결 문자열을 바꿉니다.

<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-SSFInventory-20140521115734.mdf;Initial Catalog=aspnet-SSFInventory-20140521115734;Integrated Security=True" providerName="System.Data.SqlClient" />

이 연결 문자열로 :

<add name="DefaultConnection" connectionString="Data Source=.\SQLExpress;database=SSFInventory;integrated security=true;" providerName="System.Data.SqlClient" />

그런 다음 애플리케이션을 빌드하고 실행하십시오. 사용자를 등록하면 테이블이 생성됩니다.


1
이로 인해 문제가 해결되어 데이터베이스에서 응용 프로그램 사용자를 볼 수 없었지만 기본 연결을 바꾼 후 작동했습니다.
Hassen Ch.

10

편집 : MVC5 CodePlex 프로젝트 템플릿에 대한 EF 데이터베이스 우선 ASP.NET ID.


기존 데이터베이스를 사용하고 ApplicationUser와 관계를 만들고 싶었습니다. 이것이 SQL Server를 사용하여 수행 한 방법이지만 동일한 아이디어가 아마도 모든 DB에서 작동 할 것입니다.

  1. MVC 프로젝트 만들기
  2. Web.config의 DefaultConnection 아래에 나열된 DB를 엽니 다. (aspnet- [timestamp] 또는 이와 유사한 이름으로 호출됩니다.)
  3. 데이터베이스 테이블을 스크립팅합니다.
  4. SQL Server Management Studio의 기존 데이터베이스에 스크립팅 된 테이블을 삽입합니다.
  5. ApplicationUser 에 관계를 사용자 정의하고 추가합니다 (필요한 경우).
  6. 새 웹 프로젝트 만들기> MVC> DB 첫 번째 프로젝트> EF를 사용하여 DB 가져 오기 ... 삽입 한 ID 클래스 제외.
  7. 에서 IdentityModels.cs ApplicationDbContext 변경 :base("DefaltConnection")프로젝트의 DbContext를 사용할 수 있습니다.

편집 : Asp.Net 신원 클래스 다이어그램 여기에 이미지 설명 입력


6
문제는 DBContext가 아니지만 UserManager와 RoleManager는 Microsoft.AspNet.Identity.EntityFramework.IdentityUser에서 상속 된 클래스를 기대합니다
Patrick Tran

공용 클래스 IdentityDbContext <TUser> : DbContext 여기서 TUser : Microsoft.AspNet.Identity.EntityFramework.IdentityUser. 데이터베이스를 먼저 사용할 때 생성 된 엔티티 클래스는 기본 클래스에서 상속되지 않습니다.
Patrick Tran

그런 다음 엔티티 프레임 워크로 클래스를 생성 할 때 데이터베이스에서 제외하십시오.
악취

EDMX에서 ID 테이블을 제외하면 사용자 ID에 대한 외래 키가있는 다른 클래스의 탐색 속성이 손실됩니다
Patrick Tran

34
먼저 코드로 이동하는 것을 꺼리지 않습니다. 일부 시나리오와 회사에서는 db 관리자가 코더가 아닌 기본 테이블을 생성합니다.
Patrick Tran 2013

8

IdentityUserUserStore인증을 위해에서 사용하는 코드 우선 개체이기 때문에 여기서는 쓸모가 없습니다 . 내 자신의 User개체를 정의한 후 클래스에서 IUser사용 하는 부분 클래스를 구현했습니다 UserManager. 나는 문자열 대신에 Ids를 원했기 int때문에 UserID의 toString ()을 반환합니다. 마찬가지로 나는 자본화되지 않기를 원 n했습니다 Username.

public partial class User : IUser
{

    public string Id
    {
        get { return this.UserID.ToString(); }
    }

    public string UserName
    {
        get
        {
            return this.Username;
        }
        set
        {
            this.Username = value;
        }
    }
}

당신은 결코 필요하지 않습니다 IUser. .NET에서 사용하는 유일한 인터페이스 UserManager입니다. 따라서 다른 "IUser"를 정의하려면 자체 구현을 사용하도록이 클래스를 다시 작성해야합니다.

public class UserManager<TUser> : IDisposable where TUser: IUser

당신은 지금 당신의 자신의 쓰기 UserStore코드가 우선하는 것이 모든 것의 인터페이스를 구현하는 등 사용자, 주장, 역할의 저장을 모두 처리하는 UserStore수행하고 변화 where TUser : IdentityUserwhere TUser : User여기서 "사용자"는 당신의 엔티티 객체입니다

public class MyUserStore<TUser> : IUserLoginStore<TUser>, IUserClaimStore<TUser>, IUserRoleStore<TUser>, IUserPasswordStore<TUser>, IUserSecurityStampStore<TUser>, IUserStore<TUser>, IDisposable where TUser : User
{
    private readonly MyAppEntities _context;
    public MyUserStore(MyAppEntities dbContext)
    { 
        _context = dbContext; 
    }

    //Interface definitions
}

다음은 일부 인터페이스 구현에 대한 몇 가지 예입니다.

async Task IUserStore<TUser>.CreateAsync(TUser user)
{
    user.CreatedDate = DateTime.Now;
    _context.Users.Add(user);
    await _context.SaveChangesAsync();
}

async Task IUserStore<TUser>.DeleteAsync(TUser user)
{
    _context.Users.Remove(user);
    await _context.SaveChangesAsync();
}

MVC 5 템플릿을 사용하여 AccountController를 다음과 같이 변경 했습니다.

public AccountController()
        : this(new UserManager<User>(new MyUserStore<User>(new MyAppEntities())))
{
}

이제 로그인은 자신의 테이블에서 작동합니다.


1
나는 최근에 이것을 구현할 기회가 있었고 어떤 이유로 (나는 ID의 3.0 업데이트 때문에 믿습니다) IdentityUser를 상속 한 다음 속성을 재정 의하여 로그인을 구현할 수 없었습니다. 그러나 사용자 정의 UserStore를 작성하고 IUser를 상속하면 잘 작동했습니다. 업데이트 만 제공하면 누군가 유용하다고 생각할 수 있습니다.
NAZ EKIN

모든 인터페이스 구현 또는 전체 프로젝트에 대한 링크를 제공 할 수 있습니까?
DespeiL

여기서 부분 클래스를 사용한 특별한 이유가 있습니까?
user8964654

edmx를 사용하여 모델을 생성하는 경우 partial 클래스를 사용해야합니다. 먼저 코드를 작성한다면 이것을 생략 할 수 있습니다
Shoe


3

좋은 질문.

저는 데이터베이스를 우선시하는 사람입니다. 코드 첫 번째 패러다임은 나에게 느슨해 보이며 "마이그레이션"은 오류가 발생하기 쉬운 것 같습니다.

aspnet ID 스키마를 사용자 지정하고 싶었고 마이그레이션에 신경 쓰지 않았습니다. 저는 Visual Studio 데이터베이스 프로젝트 (sqlpackage, data-dude)에 대해 잘 알고 있으며 스키마를 업그레이드하는 데 얼마나 좋은지 잘 알고 있습니다.

내 단순한 솔루션은 다음과 같습니다.

1) aspnet ID 스키마를 미러링하는 데이터베이스 프로젝트를 만듭니다. 2)이 프로젝트 (.dacpac)의 출력을 프로젝트 리소스로 사용합니다. 3) 필요한 경우 .dacpac을 배포합니다.

MVC5의 경우 ApplicationDbContext클래스를 수정하면 이것이 진행되는 것 같습니다 ...

1) 구현 IDatabaseInitializer

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IDatabaseInitializer<ApplicationDbContext> { ... }

2) 생성자에서이 클래스가 데이터베이스 초기화를 구현할 것임을 알립니다.

Database.SetInitializer<ApplicationDbContext>(this);

3) 구현 InitializeDatabase:

여기에서는 DacFX를 사용하고 .dacpac을 배포하기로 선택했습니다.

    void IDatabaseInitializer<ApplicationDbContext>.InitializeDatabase(ApplicationDbContext context)
    {
        using (var ms = new MemoryStream(Resources.Binaries.MainSchema))
        {
            using (var package = DacPackage.Load(ms, DacSchemaModelStorageType.Memory))
            {
                DacServices services = new DacServices(Database.Connection.ConnectionString);
                var options = new DacDeployOptions
                {
                    VerifyDeployment = true,
                    BackupDatabaseBeforeChanges = true,
                    BlockOnPossibleDataLoss = false,
                    CreateNewDatabase = false,
                    DropIndexesNotInSource = true,
                    IgnoreComments = true,

                };
                services.Deploy(package, Database.Connection.Database, true, options);
            }
        }
    }

2

나는 이것을 통해 몇 시간을 보냈고 마침내 여기 내 블로그 에서 공유 한 해결책을 찾았 습니다 . 기본적으로 악취 의 대답 에서 말한 모든 작업을 수행해야 하지만 한 가지 추가 사항이 있습니다. Identity Framework에 응용 프로그램 엔터티에 사용되는 Entity Framework 연결 문자열 위에 특정 SQL-Client 연결 문자열이 있는지 확인하는 것입니다.

요약하면 애플리케이션은 Identity Framework에 연결 문자열을 사용하고 애플리케이션 엔터티에 다른 연결 문자열을 사용합니다. 각 연결 문자열은 다른 유형입니다. 전체 자습서를 보려면 내 블로그 게시물을 읽어보십시오.


나는 당신이 당신의 블로그에서 언급 한 모든 것을 두 번 시도했지만 그것은 저에게 효과가 없었습니다.
Badhon Jain 2015

@Badhon 내 블로그 게시물의 지침이 제대로 작동하지 않아서 유감입니다. 내 기사를 읽은 후 성공을 거두어 수많은 사람들에게 감사의 말을 전했습니다. Microsoft가 무언가를 업데이트하면 결과에 영향을 미칠 수 있음을 항상 기억하십시오. Identity Framework 2.0을 사용하는 ASP.NET MVC 5에 대한 기사를 작성했습니다. 그 이상이면 문제가 발생할 수 있지만 지금까지 성공을 나타내는 매우 최근의 의견을 받았습니다. 나는 당신의 문제에 대해 더 듣고 싶습니다.
Daniel Eagle

나는 다시 한 번 따르려고 노력할 것입니다. 내가 직면 한 문제는 사용자 지정 데이터베이스를 사용할 수없고 자동 빌드 된 데이터베이스를 사용한다는 것입니다. 어쨌든, 나는 당신의 기사에 잘못된 것을 말하려는 것이 아닙니다. 지식을 공유해 주셔서 감사합니다.
Badhon Jain 2015

1
@Badhon 내 친구 걱정하지 마세요, 나는 당신이 기사에 잘못된 것이 있다고 생각한 적이 없습니다. 우리 모두는 다양한 엣지 케이스를 가진 독특한 상황을 가지고 있기 때문에 때때로 다른 사람들에게 효과가있는 것이 반드시 우리에게 효과가있는 것은 아닙니다. 문제를 해결할 수 있기를 바랍니다.
Daniel Eagle

2

@ JoshYates1980이 가장 간단한 대답을 가지고 있다는 것을 알았습니다.

일련의 시행 착오 끝에 Josh가 제안한 것을 수행하고 connectionString생성 된 DB 연결 문자열 로 대체했습니다 . 내가 원래 혼란 스러웠던 것은 다음 게시물이었습니다.

기존 데이터베이스에 ASP.NET MVC5 ID 인증을 추가하는 방법

@Win의 수락 된 답변이 ApplicationDbContext()연결 이름 을 변경하도록 언급 한 곳 . Entity 및 데이터베이스 연결 문자열이 생성되고 데이터베이스에 추가되는 데이터베이스 / 모델 첫 번째 접근 방식을 사용하는 경우 약간 모호합니다.Web.config 파일에 합니다.

ApplicationDbContext()연결 이름이되고 매핑 의 기본 연결로 Web.config파일. 따라서 Josh의 방법이 가장 잘 작동하지만 ApplicationDbContext()더 읽기 쉽게하려면 @Win이 처음 게시 한대로 이름을 데이터베이스 이름으로 변경하는 것이 좋습니다. connectionString에서 "DefaultConnection" 을 변경 Web.config하고 엔티티를 주석 처리하거나 제거해야합니다. 생성 된 데이터베이스 포함.

코드 예 :


1

모델 클래스를 유지하는 엔터티 모델 DLL 프로젝트가 있습니다. 또한 모든 데이터베이스 스크립트가 포함 된 데이터베이스 프로젝트를 유지합니다. 내 접근 방식은 다음과 같습니다.

1) 먼저 데이터베이스를 사용하여 EDMX가있는 자신의 프로젝트를 만듭니다.

2) db의 테이블을 스크립팅하고, localDB (데이터 연결)에 연결된 VS2013을 사용하고 스크립트를 데이터베이스 프로젝트에 복사하고, 사용자 지정 열을 추가합니다 (예 : BirthDate [DATE] not null).

3) 데이터베이스 배포

4) 모델 (EDMX) 프로젝트 업데이트 모델 프로젝트에 추가

5) 애플리케이션 클래스에 사용자 정의 열 추가

public class ApplicationUser : IdentityUser
{
    public DateTime BirthDate { get; set; }
}

MVC 프로젝트에서 AccountController는 다음을 추가했습니다.

아이덴티티 공급자는 작동을 위해 SQL 연결 문자열을 원하고, 데이터베이스에 대해 하나의 연결 문자열 만 유지하고, EF 연결 문자열에서 공급자 문자열을 추출합니다.

public AccountController()
{
   var connection = ConfigurationManager.ConnectionStrings["Entities"];
   var entityConnectionString = new EntityConnectionStringBuilder(connection.ConnectionString);
        UserManager =
            new UserManager<ApplicationUser>(
                new UserStore<ApplicationUser>(
                    new ApplicationDbContext(entityConnectionString.ProviderConnectionString)));
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.