EF Veritabanı İlk MVC5 ile ASP.NET Kimliği


88

Yeni Asp.net Kimliğini Database First ve EDMX ile kullanmak mümkün mü? Yoksa sadece kodla mı?

İşte yaptığım şey:

1) Yeni bir MVC5 Projesi yaptım ve yeni Kimliğin veritabanımda yeni Kullanıcı ve Rol tablolarını oluşturmasını sağladım.

2) Daha sonra Database First EDMX dosyamı açtım ve onunla ilgili başka tablolarım olduğu için yeni Identity Users tablosuna sürükledim.

3) EDMX'i kaydettikten sonra, Veritabanı İlk POCO oluşturucusu otomatik olarak bir Kullanıcı sınıfı oluşturacaktır. Bununla birlikte, UserManager ve RoleManager, bir Kullanıcı sınıfının yeni Kimlik ad alanından (Microsoft.AspNet.Identity.IUser) miras almasını bekler, bu nedenle POCO Kullanıcı sınıfını kullanmak işe yaramaz.

Sanırım olası bir çözüm, Kullanıcı sınıfımın IUser'dan devralınması için POCO Üretim Sınıflarımı düzenlemek olabilir mi?

Veya ASP.NET Identity yalnızca Code First Design ile uyumlu mu?

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

Güncelleme: Anders Abel'ın aşağıdaki önerisini takiben, bunu yaptım. İşe yarıyor, ama daha şık bir çözüm olup olmadığını merak ediyorum.

1) Varlık Kullanıcı sınıfımı, otomatik olarak oluşturulan varlıklar ile aynı ad alanı içinde kısmi bir sınıf oluşturarak genişlettim.

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

2) DataContext'i DBContext yerine IdentityDBContext'ten devralacak şekilde değiştirdim. EDMX'inizi her güncellediğinizde ve DBContext ve Entity sınıflarını yeniden oluşturduğunuzda, bunu tekrar buna ayarlamanız gerekeceğini unutmayın.

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

3) Otomatik oluşturulan Kullanıcı varlık sınıfınız içinde, override anahtar sözcüğünü aşağıdaki 4 alana eklemeniz veya bu alanlara IdentityUser'dan devralındıkları için yorum yapmanız gerekir (Adım 1). EDMX'inizi her güncellediğinizde ve DBContext ve Entity sınıflarını yeniden oluşturduğunuzda, bunu tekrar buna ayarlamanız gerekeceğini unutmayın.

    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
uygulamanıza ilişkin örnek kodunuz var mı? Yukarıdakileri kopyalamaya çalıştığımda, bir kullanıcı oturum açmaya veya kaydetmeye çalıştığımda bir hata alıyorum. "AspNetUser varlık türü mevcut bağlam için modelin bir parçası değil" burada AspNetUser benim Kullanıcı varlığım
Tim

AspNetUser tablosunu EDMX'inize eklediniz mi? Ayrıca, AccountController'ınızın ApplicationContext yerine MVC5Test_DBEntities (veya DB bağlamınız ne olursa olsun) kullandığından emin olun.
Patrick Tran

8
ASP.NET Identity, ____ 'dan oluşan bir yığın. Veritabanı için korkunç destek, dokümantasyon yok, yetersiz referans kısıtlamaları (SQL sunucusunda KADEMELİ DELETE AÇIK) ve kimlikler için dizeler kullanıyor (performans sorunu ve dizin parçalama). Ve bu onların 297. kimlik çerçevesi girişimi ...
DeepSpace101

1
@ DeepSpace101 Identity, Code-First ile aynı olan DB-First'ü destekler. Şablonlar önce kod yapacak şekilde ayarlanmıştır, bu nedenle bir şablondan başlarsanız bazı şeyleri değiştirmeniz gerekir. Basamaklı silme gayet iyi çalışıyor, dizeleri kolayca ints olarak değiştirebilirsiniz. Aşağıdaki cevabıma bakın.
Shoe

1
@Shoe yanılıyor olabileceğini düşündüğümü söylemeliyim. Bunun db-first'de nasıl uygulanacağına dair çalışan, kapsamlı bir örnek / öğretici bulamadım (dokümantasyon yok). API, "IdentityUserRoles" birleşim tablosuna IdentityUser.Roles özelliği aracılığıyla başvurmaya çalışır, bu da EF db-ilk ilişkisini keser çünkü birleşim tabloları varlık olarak gösterilmez (zayıf başvuru kısıtlamaları-ish). Devralınan sınıflarda tür parametreleri belirtilerek özelleştirilebildiğinden, kimlik dizeleri konusunda aynı fikirde değilim. Özetlemek gerekirse, akıllarında ilk olarak DB yokmuş gibi görünüyor.
Lopsided

Yanıtlar:


16

Kimlik sistemini POCO ve Database First ile kullanmak mümkün olmalı, ancak birkaç ince ayar yapmanız gerekecek:

  1. Varlık sınıflarını oluşturmak için POCO üretimi için .tt dosyasını güncelleyin partial. Bu, ayrı bir dosyada ek uygulama sağlamanızı mümkün kılacaktır.
  2. UserBaşka bir dosyada sınıfın kısmi uygulamasını yapın

 

partial User : IUser
{
}

Bu, Usersınıfın gerçek oluşturulan dosyalara dokunmadan doğru arayüzü uygulamasını sağlayacaktır (oluşturulan dosyaları düzenlemek her zaman kötü bir fikirdir).


Teşekkürler. Bunu bir denemem ve işe yarayıp yaramadığını bildirmem gerekecek.
Patrick Tran

Bahsettiğiniz şeyi denedim. Güncellenen bilgiler için gönderime bakın ... ancak çözüm çok zarif değildi: /
Patrick Tran

Ben de aynı sorunu yaşıyorum. Görünüşe göre DB-first üzerindeki dokümantasyon çok seyrek. Bu güzel bir öneri ama bence haklısın, pek işe yaramıyor
Phil

4
Henüz hack olmayan bir çözüm var mı?
user20358

Onion Architecture kullanıyorum ve tüm POCO'lar Core'da. Orada IUser kullanılması tavsiye edilmez. Yani başka bir çözüm var mı?
Usman Khalid

13

Adımlarım çok benzer ama paylaşmak istedim.

1) Yeni bir MVC5 projesi oluşturun

2) Yeni bir Model.edmx oluşturun. Yeni bir veritabanı olsa ve hiç tablosu olmasa bile.

3) web.config dosyasını düzenleyin ve oluşturulan bu bağlantı dizesini değiştirin:

<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" />

bu bağlantı dizesiyle:

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

Daha sonra uygulamayı oluşturun ve çalıştırın. Bir kullanıcı kaydedin ve ardından tablolar oluşturulacaktır.


1
bu bir sorunu çözdü, uygulama kullanıcısını veritabanında göremedim, ancak varsayılan bağlantıyı değiştirdikten sonra çalıştı.
Hassen Ch.

10

DÜZENLEME: MVC5 CodePlex Proje Şablonu için EF Veritabanı First ile ASP.NET Kimliği.


Mevcut bir veritabanını kullanmak ve ApplicationUser ile ilişkiler oluşturmak istedim. Bunu SQL Server kullanarak böyle yaptım ama aynı fikir muhtemelen herhangi bir DB ile de işe yarar.

  1. Bir MVC Projesi Oluşturun
  2. Web.config dosyasında DefaultConnection altında listelenen DB'yi açın. Adı (aspnet- [zaman damgası] veya bunun gibi bir şey.)
  3. Veritabanı tablolarını kodlayın.
  4. Komut dosyası oluşturulmuş tabloları SQL Server Management Studio'daki mevcut veritabanına ekleyin.
  5. ApplicationUser ile ilişkileri özelleştirin ve ekleyin (gerekirse).
  6. Yeni Web Projesi Oluştur> MVC> İlk DB Projesi> EF ile DB İçe Aktar ... Eklediğiniz Kimlik Sınıfları hariç.
  7. Gelen IdentityModels.cs ApplicationDbContext değiştirmek :base("DefaltConnection")projenizin DBContext kullanmak.

Düzenleme: Asp.Net Kimlik Sınıfı Diyagramı görüntü açıklamasını buraya girin


6
Sorun DBContext değil, ama UserManager ve roleManager bir sınıf beklediklerini olduğunu Microsoft.AspNet.Identity.EntityFramework.IdentityUser devralır
Patrick Tran

public class IdentityDbContext <TUser>: DbContext burada TUser: Microsoft.AspNet.Identity.EntityFramework.IdentityUser. Veritabanını ilk kullanırken, üretilen varlık sınıfları herhangi bir temel sınıftan miras almaz.
Patrick Tran

Ardından, varlık çerçevesiyle sınıfları oluşturduğunuzda bunları veritabanından hariç tutun.
kokar

Kimlik tablolarını EDMX'ten hariç tutarsanız, Kullanıcı Kimliğinizin yabancı anahtarları olan diğer sınıflardaki Gezinme özelliklerini kaybedersiniz
Patrick Tran

35
Önce koda geçme konusunda isteksiz değilim ... Sadece bazı senaryolarda ve şirketlerde, db yöneticisi kodlayıcı değil temel tabloları oluşturur.
Patrick Tran

8

IdentityUserburada değersizdir çünkü UserStorekimlik doğrulaması için kullanılan kod ilk nesnedir . Kendi nesnemi tanımladıktan sonra , sınıf tarafından kullanılan Useruygulayan kısmi bir sınıf uyguladım . Benim istediğim olmaya s Sadece KullanıcıNo en toString dönmek böylece yerine dize (). Benzer şekilde , sermayesiz olmak istedim .IUserUserManagerIdintnUsername

public partial class User : IUser
{

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

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

Hiç gerek yok IUser. Bu yalnızca UserManager. Dolayısıyla, farklı bir "IUser" tanımlamak istiyorsanız, kendi uygulamanızı kullanmak için bu sınıfı yeniden yazmanız gerekir.

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

Artık kendi yazma UserStorekod önce bu her şeyin arayüzleri uygulamak vb kullanıcıları, istemlerin, roller, depolanması tüm işleyen UserStoreyapar ve değişim where TUser : IdentityUseriçin where TUser : Userburada "Kullanıcı", tüzel nesnesidir

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
}

İşte bazı arayüz uygulamalarıyla ilgili birkaç örnek

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 şablonunu kullanarak, şöyle AccountControllergörünecek şekilde değiştirdim .

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

Şimdi giriş yapmak kendi tablolarınızla çalışmalıdır.


1
Son zamanlarda bunu uygulama şansım oldu ve bazı nedenlerden dolayı (kimliğin 3.0 güncellemesinden dolayı) IdentityUser'ı devralarak ve ardından özellikleri geçersiz kılarak oturum açma işlemini gerçekleştiremedim; ancak özel bir UserStore yazmak ve IUser'ı devralmak iyi çalıştı; Sadece bir güncelleme yaparak, belki birisi bunu faydalı bulabilir.
Naz Ekin

Tüm arayüz uygulamaları için veya tam proje için bağlantı verebilir misiniz?
DespeiL

Burada kısmi bir sınıf kullanmanızın belirli bir nedeni var mı?
user8964654

Modellerinizi oluşturmak için bir edmx kullanıyorsanız, kısmi bir sınıf kullanmalısınız. Önce kod yapıyorsanız, bunu atlayabilirsiniz
Shoe


3

İyi soru.

Ben daha çok veri tabanında birinci kişiyim. İlk kod paradigması bana gevşek gibi görünüyor ve "göçler" çok fazla hataya açık görünüyor.

Aspnet kimlik şemasını özelleştirmek ve geçişlerden rahatsız olmamak istedim. Visual Studio veritabanı projeleri (sqlpackage, data-dude) ve şemaları yükseltmede nasıl oldukça iyi bir iş çıkardığı konusunda bilgiliyim.

Benim basit çözümüm şudur:

1) aspnet kimlik şemasını yansıtan bir veritabanı projesi oluşturun 2) bu projenin çıktısını (.dacpac) bir proje kaynağı olarak kullanın 3) .dacpac'i gerektiğinde dağıtın

MVC5 için, ApplicationDbContextsınıfı değiştirmek bunu devam ettirecek gibi görünüyor ...

1) Uygulama IDatabaseInitializer

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

2) Yapıcıda, bu sınıfın veritabanı başlatmayı uygulayacağını işaret edin:

Database.SetInitializer<ApplicationDbContext>(this);

3) Uygulama InitializeDatabase:

Burada, DacFX kullanmayı ve .dacpac'ımı dağıtmayı seçtim

    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

Bunun üzerinde birkaç saat çalıştım ve sonunda buradaki blogumda paylaştığım bir çözüm buldum . Temel olarak, kokuşmuş yanıtta söylenen her şeyi yapmanız gerekir, ancak ek bir şeyle: Identity Framework'ün uygulama varlıklarınız için kullanılan Entity Framework bağlantı dizesinin üzerinde belirli bir SQL-İstemci bağlantı dizesine sahip olmasını sağlamak.

Özetle, uygulamanız Identity Framework için bir bağlantı dizesi ve uygulama varlıklarınız için başka bir bağlantı dizesi kullanır. Her bağlantı dizesi farklı bir türdendir. Tam bir eğitim için blog yazımı okuyun.


Blogunuzda bahsettiğiniz her şeyi iki kez denedim, benim için işe yaramadı.
Badhon Jain

@Badhon Blog yazımdaki talimatlar senin için işe yaramadı. Makalemden sonra başarıya ulaşan sayısız insan teşekkürlerini dile getirdi. Microsoft bir şeyi güncellerse, sonucu etkileyebileceğini her zaman unutmayın. Identity Framework 2.0 ile ASP.NET MVC 5 için bir makale yazdım. Bunun ötesinde herhangi bir şey sorun yaşayabilir, ancak şimdiye kadar başarıyı gösteren çok yeni yorumlar aldım. Sorunun hakkında daha çok şey duymak isterim.
Daniel Kartal

Bir kez daha takip etmeye çalışacağım, karşılaştığım sorun, özel veritabanımı kullanamamak, otomatik oluşturulan veritabanını kullanmak. Her neyse, makalende yanlış bir şey söylemek istemedim. Bilgilerinizi paylaştığınız için teşekkür ederiz.
Badhon Jain

1
@Badhon Endişelenme arkadaşım, makaleyle ilgili yanlış bir şey olduğunu söylediğini hiç hissetmedim. Hepimizin çeşitli uç vakalarla benzersiz durumları vardır, bu nedenle bazen başkaları için işe yarayan şey bizim için mutlaka işe yaramayabilir. Umarım probleminizi çözmüşsünüzdür.
Daniel Eagle

2

@ JoshYates1980'in en basit cevaba sahip olduğunu buldum.

Bir dizi deneme ve hatadan sonra, Josh'un önerdiği şeyi yaptım ve connectionStringoluşturduğum DB bağlantı dizesi ile değiştirdim . aslen şu yazı hakkında kafam karıştı:

Mevcut veritabanına ASP.NET MVC5 Kimlik Kimlik Doğrulaması ekleme

@ Win'den kabul edilen yanıtın ApplicationDbContext()bağlantı adını değiştirdiği belirtildi . Varlık ve veritabanı bağlantı dizesinin oluşturulduğu ve Web.configdosyaya eklendiği bir Veritabanı / Model ilk yaklaşımı kullanıyorsanız, bu biraz belirsizdir .

ApplicationDbContext()Bağlantı adıdır eşleştirilmiş varsayılan bağlantısına Web.configdosyası. Bu nedenle, Josh'un yöntemi en iyi şekilde çalışır, ancak ApplicationDbContext()daha okunaklı hale getirmek için, veritabanı adınızı @Win orijinal olarak gönderilmiş olarak değiştirmenizi öneririm connectionString, "DefaultConnection" için "DefaultConnection" ifadesini değiştirdiğinizden emin olun Web.configve yorum yapın ve / veya Varlığı kaldırın. oluşturulan veritabanı içerir.

Kod Örnekleri:


1

Model sınıfımızı tuttuğumuz bir Entity Model DLL projemiz var. Ayrıca tüm veritabanı betikleri ile bir Veritabanı Projesi tutuyoruz. Benim yaklaşımım aşağıdaki gibiydi

1) Önce veritabanını kullanarak EDMX'e sahip kendi projenizi oluşturun

2) Veritabanınızdaki tabloları kodlayın, VS2013'ü localDB'ye (Veri Bağlantıları) bağlı olarak kullandım ve komut dosyasını veritabanı projesine kopyaladım, herhangi bir özel sütun ekleyin, örneğin Doğum Tarihi [DATE] boş değil

3) Veritabanını dağıtın

4) Model (EDMX) projesini güncelleyin Model projesine ekleyin

5) Uygulama sınıfına herhangi bir özel sütun ekleyin

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

MVC projesinde AccountController şunları ekledi:

Kimlik Sağlayıcı, çalışması için bir SQL Bağlantı Dizesi istiyor, veritabanı için yalnızca 1 bağlantı dizesi tutuyor, sağlayıcı dizesini EF bağlantı dizesinden ayıklıyor

public AccountController()
{
   var connection = ConfigurationManager.ConnectionStrings["Entities"];
   var entityConnectionString = new EntityConnectionStringBuilder(connection.ConnectionString);
        UserManager =
            new UserManager<ApplicationUser>(
                new UserStore<ApplicationUser>(
                    new ApplicationDbContext(entityConnectionString.ProviderConnectionString)));
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.