Czy można używać nowej tożsamości Asp.net z usługami Database First i EDMX? Czy tylko z kodem na początku?
Oto co zrobiłem:
1) Zrobiłem nowy projekt MVC5 i poleciłem, aby nowa tożsamość utworzyła nowe tabele użytkowników i ról w mojej bazie danych.
2) Następnie otworzyłem mój plik Database First EDMX i przeciągnąłem do nowej tabeli Identity Users, ponieważ mam inne tabele, które się z nią wiążą.
3) Po zapisaniu EDMX, generator Database First POCO automatycznie utworzy klasę użytkownika. Jednak UserManager i RoleManager oczekują klasy User dziedziczącej z nowej przestrzeni nazw tożsamości (Microsoft.AspNet.Identity.IUser), więc użycie klasy POCO User nie będzie działać.
Wydaje mi się, że możliwym rozwiązaniem jest edycja moich klas generacji POCO, aby moja klasa użytkownika dziedziczyła po IUser?
A może ASP.NET Identity jest zgodne tylko z Code First Design?
+++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++
Aktualizacja: Postępując zgodnie z sugestią Andersa Abla poniżej, zrobiłem to. To działa, ale zastanawiam się, czy istnieje bardziej eleganckie rozwiązanie.
1) Rozszerzyłem klasę użytkownika jednostki, tworząc klasę częściową w tej samej przestrzeni nazw, co moje automatycznie generowane jednostki.
namespace MVC5.DBFirst.Entity
{
public partial class AspNetUser : IdentityUser
{
}
}
2) Zmieniłem mój DataContext na dziedziczenie z IdentityDBContext zamiast DBContext. Zauważ, że za każdym razem, gdy aktualizujesz EDMX i ponownie generujesz klasy DBContext i Entity, będziesz musiał ustawić to z powrotem na to.
public partial class MVC5Test_DBEntities : IdentityDbContext<AspNetUser> //DbContext
3) W ramach automatycznie generowanej klasy encji użytkownika musisz dodać słowo kluczowe override do następujących 4 pól lub skomentować te pola, ponieważ są one dziedziczone po IdentityUser (krok 1). Zauważ, że za każdym razem, gdy aktualizujesz EDMX i ponownie generujesz klasy DBContext i Entity, będziesz musiał ustawić to z powrotem na to.
override public string Id { get; set; }
override public string UserName { get; set; }
override public string PasswordHash { get; set; }
override public string SecurityStamp { get; set; }
źródło
Odpowiedzi:
Powinno być możliwe użycie systemu tożsamości z POCO i Database First, ale będziesz musiał wprowadzić kilka poprawek:
partial
. Umożliwi to dostarczenie dodatkowej implementacji w osobnym pliku.User
klasy w innym plikupartial User : IUser { }
To sprawi, że
User
klasa zaimplementuje właściwy interfejs, bez dotykania faktycznie wygenerowanych plików (edycja wygenerowanych plików jest zawsze złym pomysłem).źródło
Moje kroki są bardzo podobne, ale chciałem się nimi podzielić.
1) Utwórz nowy projekt MVC5
2) Utwórz nowy plik Model.edmx. Nawet jeśli jest to nowa baza danych i nie ma tabel.
3) Edytuj plik web.config i zastąp ten wygenerowany ciąg połączenia:
<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" />
z tym ciągiem połączenia:
<add name="DefaultConnection" connectionString="Data Source=.\SQLExpress;database=SSFInventory;integrated security=true;" providerName="System.Data.SqlClient" />
Następnie skompiluj i uruchom aplikację. Zarejestruj użytkownika, a następnie zostaną utworzone tabele.
źródło
EDYCJA: ASP.NET Identity z EF Database First dla szablonu projektu MVC5 CodePlex.
Chciałem użyć istniejącej bazy danych i stworzyć relacje z ApplicationUser. W ten sposób zrobiłem to przy użyciu SQL Server, ale ten sam pomysł prawdopodobnie zadziałałby z każdą bazą danych.
:base("DefaltConnection")
aby używał DbContext projektu.Edycja: Diagram klas tożsamości Asp.Net
źródło
IdentityUser
jest tutaj bezwartościowy, ponieważ jest to pierwszy obiekt kodu używany przezUserStore
do uwierzytelniania. Po zdefiniowaniu własnegoUser
obiektu zaimplementowałem częściową klasę, która implementujeIUser
używaną przezUserManager
klasę. Chciałem, aby mojeId
s byłyint
zamiast ciągu, więc po prostu zwracam toString () z UserID. Podobnie chciałemn
sięUsername
być uncapitalized.public partial class User : IUser { public string Id { get { return this.UserID.ToString(); } } public string UserName { get { return this.Username; } set { this.Username = value; } } }
W żadnym wypadku nie potrzebujesz
IUser
. To tylko interfejs używany przezUserManager
. Więc jeśli chcesz zdefiniować inny "IUser", musisz przepisać tę klasę, aby używała własnej implementacji.public class UserManager<TUser> : IDisposable where TUser: IUser
Teraz napisać własną rękę
UserStore
, która obsługuje wszystkie przechowywania użytkowników, roszczeń, ról itp Wdrożenie interfejsów wszystkiego, że kod, najpierwUserStore
robi i zmianawhere TUser : IdentityUser
nawhere TUser : User
miarę „Użytkownik” to Twój obiekt podmiotpublic 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 }
Oto kilka przykładów niektórych implementacji interfejsu
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(); }
Korzystając z szablonu MVC 5, zmieniłem
AccountController
wygląd tak.public AccountController() : this(new UserManager<User>(new MyUserStore<User>(new MyAppEntities()))) { }
Teraz logowanie powinno działać z własnymi tabelami.
źródło
Spójrz na ten projekt na GitHub: https://github.com/KriaSoft/AspNet.Identity
Co zawiera:
Zobacz również : Jak utworzyć dostawcę Database-First dla ADO.NET Identity
źródło
Dobre pytanie.
Jestem raczej pierwszą osobą w bazach danych. Pierwszy paradygmat kodu wydaje mi się luźny, a „migracje” wydają się zbyt podatne na błędy.
Chciałem dostosować schemat tożsamości aspnet i nie przejmować się migracjami. Jestem dobrze zorientowany w projektach baz danych Visual Studio (sqlpackage, data-dude) i jak radzi sobie całkiem nieźle z uaktualnianiem schematów.
Moje uproszczone rozwiązanie to:
1) Utwórz projekt bazy danych, który odzwierciedla schemat tożsamości aspnet 2) użyj danych wyjściowych tego projektu (.dacpac) jako zasobu projektu 3) Wdróż .dacpac w razie potrzeby
W przypadku MVC5 modyfikacja
ApplicationDbContext
klasy wydaje się działać ...1) Wdrożenie
IDatabaseInitializer
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IDatabaseInitializer<ApplicationDbContext> { ... }
2) W konstruktorze zasygnalizuj, że ta klasa zaimplementuje inicjalizację bazy danych:
Database.SetInitializer<ApplicationDbContext>(this);
3) Wdrożenie
InitializeDatabase
:Tutaj zdecydowałem się użyć DacFX i wdrożyć mój .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); } } }
źródło
Pracując nad tym spędziłem kilka godzin iw końcu znalazłem rozwiązanie, które podzieliłem się tutaj na moim blogu . Zasadniczo musisz zrobić wszystko, co zostało powiedziane w odpowiedzi smrodu , ale z jedną dodatkową rzeczą: upewnij się, że Identity Framework ma określone parametry połączenia SQL-Client na szczycie parametrów połączenia Entity Framework używanych dla jednostek aplikacji.
Podsumowując, aplikacja będzie używać parametrów połączenia dla platformy Identity Framework i innych dla jednostek aplikacji. Każdy ciąg połączenia jest innego typu. Przeczytaj mój wpis na blogu, aby zapoznać się z pełnym samouczkiem.
źródło
Odkryłem, że @ JoshYates1980 ma najprostszą odpowiedź.
Po serii prób i błędów zrobiłem to, co zasugerował Josh i zastąpiłem
connectionString
wygenerowanym ciągiem połączenia z bazą danych. pierwotnie byłem zdezorientowany następującym postem:Jak dodać uwierzytelnianie tożsamości ASP.NET MVC5 do istniejącej bazy danych
Gdzie zaakceptowana odpowiedź od @Win wskazywała na zmianę
ApplicationDbContext()
nazwy połączenia. Jest to trochę niejasne, jeśli używasz Entity i pierwszego podejścia Database / Model, w którym parametry połączenia z bazą danych są generowane i dodawane doWeb.config
pliku.Nazwa
ApplicationDbContext()
połączenia jest mapowana na domyślne połączenie wWeb.config
pliku. Dlatego metoda Josha działa najlepiej, ale aby uczynić jąApplicationDbContext()
bardziej czytelną, sugerowałbym zmianę nazwy na nazwę bazy danych zgodnie z pierwotnym opublikowaniem @Win, upewniając się, że zmienisz opcjęconnectionString
„DefaultConnection” wWeb.config
i skomentuj i / lub usuń jednostkę wygenerowana baza danych zawiera.Przykłady kodu:
źródło
Mamy projekt DLL modelu encji, w którym przechowujemy naszą klasę modelu. Prowadzimy również projekt bazy danych ze wszystkimi skryptami bazy danych. Moje podejście było następujące
1) Stwórz swój własny projekt, w którym EDMX używa najpierw bazy danych
2) Skryptuj tabele w swojej bazie danych, użyłem VS2013 połączonego z localDB (Połączenia danych) i skopiowałem skrypt do projektu bazy danych, dodaj dowolne niestandardowe kolumny, np. Data urodzenia [DATA] nie null
3) Wdróż bazę danych
4) Zaktualizuj projekt modelu (EDMX) Dodaj do projektu modelu
5) Dodaj dowolne kolumny niestandardowe do klasy aplikacji
public class ApplicationUser : IdentityUser { public DateTime BirthDate { get; set; } }
W projekcie MVC AccountController dodano następujące elementy:
Dostawca tożsamości chce, aby parametry połączenia SQL działały, aby zachować tylko 1 parametry połączenia dla bazy danych, wyodrębnij ciąg dostawcy z parametrów połączenia 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))); }
źródło