ASP.NET पहचान DbContext भ्रम


196

एक डिफ़ॉल्ट MVC 5 ऐप IdentityModels.cs में कोड के इस टुकड़े के साथ आता है - कोड का यह टुकड़ा डिफ़ॉल्ट टेम्पलेट के लिए सभी ASP.NET पहचान कार्यों के लिए है:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }
}

अगर मैं एंटिटी फ्रेमवर्क के साथ विचारों का उपयोग करके एक नया नियंत्रक बनाता हूं और संवाद में "नया डेटा संदर्भ ..." बनाता हूं, तो मुझे यह मेरे लिए उत्पन्न होता है:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace WebApplication1.Models
{
    public class AllTheOtherStuffDbContext : DbContext
    {
        // You can add custom code to this file. Changes will not be overwritten.
        // 
        // If you want Entity Framework to drop and regenerate your database
        // automatically whenever you change your model schema, please use data migrations.
        // For more information refer to the documentation:
        // http://msdn.microsoft.com/en-us/data/jj591621.aspx

        public AllTheOtherStuffDbContext() : base("name=AllTheOtherStuffDbContext")
        {
        }

        public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; }

    }
} 

अगर मैं EF का उपयोग करके किसी अन्य नियंत्रक + दृश्य को मचान करता हूं, उदाहरण के लिए एक पशु मॉडल के लिए कहता हूं, तो इस नई पंक्ति को public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; }इस तरह से स्वत: प्राप्त किया जाएगा :

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace WebApplication1.Models
{
    public class AllTheOtherStuffDbContext : DbContext
    {
        // You can add custom code to this file. Changes will not be overwritten.
        // 
        // If you want Entity Framework to drop and regenerate your database
        // automatically whenever you change your model schema, please use data migrations.
        // For more information refer to the documentation:
        // http://msdn.microsoft.com/en-us/data/jj591621.aspx

        public AllTheOtherStuffDbContext() : base("name=AllTheOtherStuffDbContext")
        {
        }

        public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; }
        public System.Data.Entity.DbSet<WebApplication1.Models.Animal> Animals { get; set; }

    }
} 

ApplicationDbContext(सभी ASP.NET पहचान सामग्री के लिए) IdentityDbContextजिसमें से विरासत में मिला है DbContextAllOtherStuffDbContext(अपने सामान के लिए) से विरासत में मिला है DbContext

तो मेरा सवाल है:

इन दोनों में से कौन सा ( ApplicationDbContextऔर AllOtherStuffDbContext) मुझे अपने सभी अन्य मॉडलों के लिए उपयोग करना चाहिए? या क्या मुझे सिर्फ डिफ़ॉल्ट ऑटोजेनरेटेड का उपयोग ApplicationDbContextकरना चाहिए क्योंकि यह एक समस्या का उपयोग नहीं करना चाहिए क्योंकि यह आधार वर्ग से निकलता है DbContext, या कुछ ओवरहेड होगा? आपको DbContextअपने सभी मॉडलों के लिए अपने ऐप में केवल एक ऑब्जेक्ट का उपयोग करना चाहिए (मैंने इसे कहीं पढ़ा है) इसलिए मुझे भी ApplicationDbContextऔर AllOtherStuffDbContextएक ही ऐप में दोनों का उपयोग करने पर विचार नहीं करना चाहिए ? या ASP.NET पहचान के साथ MVC 5 में सबसे अच्छा अभ्यास क्या है?


1
वैसे; यह डॉक्यूमेंट को स्कैन करते समय मेरी आँखों के लिए अनावश्यक है और अनावश्यक है: Public System.Data.Entity.DbSet <WebApplication1.Models.Movie> Movies {get; सेट; } - System.Data.Entity और WebApplication1.odels भाग। क्या इसे घोषणा से हटाया नहीं जा सकता है और इसके बजाय उपयोग बयान अनुभाग में नामस्थान जोड़ सकते हैं?
पूसबूट्स

पूस - आपकी टिप्पणी के लिए हाँ। यह ठीक काम करना चाहिए।
SB2055

यह एक अच्छा और कामकाजी, उदाहरण (MVC 6) है और MongoDB.Driver (> = v2.1.0) github.com/saan800-SanSoft के
स्टैनिस्लाव Prusac 13

जवाबों:


178

मैं IdentityDbContext से विरासत में एक एकल संदर्भ वर्ग का उपयोग करूंगा। इस तरह से आप संदर्भ को अपनी कक्षाओं और IdentityUser और IdentityDbContext के रोल्स के बीच किसी भी संबंध के बारे में पता कर सकते हैं। IdentityDbContext में बहुत कम ओवरहेड है, यह मूल रूप से दो DbSets के साथ एक नियमित DbContext है। उपयोगकर्ताओं के लिए एक और भूमिकाओं के लिए एक।


52
यह एकल MVC5 परियोजना के लिए है, लेकिन वांछनीय नहीं है जब व्युत्पन्न DbContext को कई परियोजनाओं के बीच साझा किया जाता है, कुछ MVC5 नहीं, जहां कुछ को पहचान समर्थन की आवश्यकता नहीं होती है।
डेव

आसान रखरखाव और बेहतर संबंधपरक अखंडता के लिए एक ही डेटाबेस के लिए वोट दिया गया। क्योंकि उपयोगकर्ता इकाई और भूमिका इकाई आसानी से अन्य एप्लिकेशन ऑब्जेक्ट्स से संबंधित होगी।
AIBMer

6
@ डेव - यह दो अलग-अलग संदर्भों का उपयोग करके उपयोगकर्ता डेटा के विभाजन को जटिल बनाता है। क्या आपका MVC ऐप विभाजन डेटा उपयोगकर्ता द्वारा करता है, लेकिन अन्य ऐप नहीं करते हैं। समान डेटा लेयर को साझा करना आम है, लेकिन मुझे नहीं लगता कि यह सामान्य है कि कुछ प्रोजेक्ट को उपयोगकर्ता द्वारा निर्धारित डेटा की आवश्यकता होती है, और कुछ नहीं।
रिकएंडएमएसएफटी

1
क्या किसी को एमवीसी प्रोजेक्ट से ApplicationDBContext निकालने और मौजूदा EF लेयर में शामिल करने के बारे में पता है? दोनों को मिलाना, जैसा कि ऊपर वर्णित है, सही दृष्टिकोण प्रतीत होता है, लेकिन मैं समय की कमी वाली परियोजना पर काम कर रहा हूं। मैं इसके माध्यम से पहली बार सही करना चाहता हूं, लेकिन मेरे सामने झूठ बोलने वाले सभी
गधों

7
लगभग एक घंटे की तलाश के बाद इस उत्तर ने मुझे सही दिशा में आने का संकेत दिया - लेकिन मुझे यकीन नहीं था कि इसे कैसे लागू किया जाए (एक बहुत शाब्दिक व्यक्ति के लिए)। इसलिए अगर यह किसी और की मदद करता है, तो मैंने पाया कि सबसे सरल तरीका है IdentityModels.cs को खोलना, और ApplicationDbContext क्लास में अपना नया DbSet जोड़ना।
शॉनब

45

IdentityDbContext के बारे में बहुत भ्रम है , Stackoverflow में एक त्वरित खोज और आपको ये प्रश्न मिलेंगे:
" Asp.Net IdentityDbContext एक ब्लैक-बॉक्स क्यों है?
विज़ुअल स्टूडियो 2013 AspNet आइडेंटिटी का उपयोग करते समय मैं तालिका के नाम कैसे बदल सकता हूं?
मर्ज IdentityDbContext साथ MyDbContext "

इन सभी सवालों के जवाब के लिए हमें यह समझने की जरूरत है कि IdentityDbContext सिर्फ DbChtext से विरासत में मिला वर्ग है।
आइए IdentityDbContext स्रोत पर एक नज़र डालें :

/// <summary>
/// Base class for the Entity Framework database context used for identity.
/// </summary>
/// <typeparam name="TUser">The type of user objects.</typeparam>
/// <typeparam name="TRole">The type of role objects.</typeparam>
/// <typeparam name="TKey">The type of the primary key for users and roles.</typeparam>
/// <typeparam name="TUserClaim">The type of the user claim object.</typeparam>
/// <typeparam name="TUserRole">The type of the user role object.</typeparam>
/// <typeparam name="TUserLogin">The type of the user login object.</typeparam>
/// <typeparam name="TRoleClaim">The type of the role claim object.</typeparam>
/// <typeparam name="TUserToken">The type of the user token object.</typeparam>
public abstract class IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : DbContext
    where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin>
    where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
    where TKey : IEquatable<TKey>
    where TUserClaim : IdentityUserClaim<TKey>
    where TUserRole : IdentityUserRole<TKey>
    where TUserLogin : IdentityUserLogin<TKey>
    where TRoleClaim : IdentityRoleClaim<TKey>
    where TUserToken : IdentityUserToken<TKey>
{
    /// <summary>
    /// Initializes a new instance of <see cref="IdentityDbContext"/>.
    /// </summary>
    /// <param name="options">The options to be used by a <see cref="DbContext"/>.</param>
    public IdentityDbContext(DbContextOptions options) : base(options)
    { }

    /// <summary>
    /// Initializes a new instance of the <see cref="IdentityDbContext" /> class.
    /// </summary>
    protected IdentityDbContext()
    { }

    /// <summary>
    /// Gets or sets the <see cref="DbSet{TEntity}"/> of Users.
    /// </summary>
    public DbSet<TUser> Users { get; set; }

    /// <summary>
    /// Gets or sets the <see cref="DbSet{TEntity}"/> of User claims.
    /// </summary>
    public DbSet<TUserClaim> UserClaims { get; set; }

    /// <summary>
    /// Gets or sets the <see cref="DbSet{TEntity}"/> of User logins.
    /// </summary>
    public DbSet<TUserLogin> UserLogins { get; set; }

    /// <summary>
    /// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles.
    /// </summary>
    public DbSet<TUserRole> UserRoles { get; set; }

    /// <summary>
    /// Gets or sets the <see cref="DbSet{TEntity}"/> of User tokens.
    /// </summary>
    public DbSet<TUserToken> UserTokens { get; set; }

    /// <summary>
    /// Gets or sets the <see cref="DbSet{TEntity}"/> of roles.
    /// </summary>
    public DbSet<TRole> Roles { get; set; }

    /// <summary>
    /// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims.
    /// </summary>
    public DbSet<TRoleClaim> RoleClaims { get; set; }

    /// <summary>
    /// Configures the schema needed for the identity framework.
    /// </summary>
    /// <param name="builder">
    /// The builder being used to construct the model for this context.
    /// </param>
    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<TUser>(b =>
        {
            b.HasKey(u => u.Id);
            b.HasIndex(u => u.NormalizedUserName).HasName("UserNameIndex").IsUnique();
            b.HasIndex(u => u.NormalizedEmail).HasName("EmailIndex");
            b.ToTable("AspNetUsers");
            b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken();

            b.Property(u => u.UserName).HasMaxLength(256);
            b.Property(u => u.NormalizedUserName).HasMaxLength(256);
            b.Property(u => u.Email).HasMaxLength(256);
            b.Property(u => u.NormalizedEmail).HasMaxLength(256);
            b.HasMany(u => u.Claims).WithOne().HasForeignKey(uc => uc.UserId).IsRequired();
            b.HasMany(u => u.Logins).WithOne().HasForeignKey(ul => ul.UserId).IsRequired();
            b.HasMany(u => u.Roles).WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
        });

        builder.Entity<TRole>(b =>
        {
            b.HasKey(r => r.Id);
            b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex");
            b.ToTable("AspNetRoles");
            b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken();

            b.Property(u => u.Name).HasMaxLength(256);
            b.Property(u => u.NormalizedName).HasMaxLength(256);

            b.HasMany(r => r.Users).WithOne().HasForeignKey(ur => ur.RoleId).IsRequired();
            b.HasMany(r => r.Claims).WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
        });

        builder.Entity<TUserClaim>(b => 
        {
            b.HasKey(uc => uc.Id);
            b.ToTable("AspNetUserClaims");
        });

        builder.Entity<TRoleClaim>(b => 
        {
            b.HasKey(rc => rc.Id);
            b.ToTable("AspNetRoleClaims");
        });

        builder.Entity<TUserRole>(b => 
        {
            b.HasKey(r => new { r.UserId, r.RoleId });
            b.ToTable("AspNetUserRoles");
        });

        builder.Entity<TUserLogin>(b =>
        {
            b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
            b.ToTable("AspNetUserLogins");
        });

        builder.Entity<TUserToken>(b => 
        {
            b.HasKey(l => new { l.UserId, l.LoginProvider, l.Name });
            b.ToTable("AspNetUserTokens");
        });
    }
}


स्रोत कोड के आधार पर यदि हम अपने DbContext के साथ IdentityDbContext को मर्ज करना चाहते हैं तो हमारे पास दो विकल्प हैं:

पहला विकल्प:
एक DbContext बनाएं जो IdentityDbContext से विरासत में मिले और कक्षाओं तक पहुंच हो।

   public class ApplicationDbContext 
    : IdentityDbContext
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }

    static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    // Add additional items here as needed
}


अतिरिक्त नोट्स:

1) हम निम्नलिखित समाधान के साथ asp.net Identity default table नाम भी बदल सकते हैं:

    public class ApplicationDbContext : IdentityDbContext
    {    
        public ApplicationDbContext(): base("DefaultConnection")
        {
        }

        protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<IdentityUser>().ToTable("user");
            modelBuilder.Entity<ApplicationUser>().ToTable("user");

            modelBuilder.Entity<IdentityRole>().ToTable("role");
            modelBuilder.Entity<IdentityUserRole>().ToTable("userrole");
            modelBuilder.Entity<IdentityUserClaim>().ToTable("userclaim");
            modelBuilder.Entity<IdentityUserLogin>().ToTable("userlogin");
        }
    }

2) इसके अलावा हम प्रत्येक वर्ग का विस्तार कर सकते हैं और 'IdentityUser', 'IdentityRole' जैसी कक्षाओं में किसी भी संपत्ति को जोड़ सकते हैं, ...

    public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
    public ApplicationRole() 
    {
        this.Id = Guid.NewGuid().ToString();
    }

    public ApplicationRole(string name)
        : this()
    {
        this.Name = name;
    }

    // Add any custom Role properties/code here
}


// Must be expressed in terms of our custom types:
public class ApplicationDbContext 
    : IdentityDbContext<ApplicationUser, ApplicationRole, 
    string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }

    static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    // Add additional items here as needed
}

समय बचाने के लिए हम सभी वर्गों का विस्तार करने के लिए AspNet Identity 2.0 एक्स्टेंसिबल प्रोजेक्ट टेम्पलेट का उपयोग कर सकते हैं ।

दूसरा विकल्प:(अनुशंसित नहीं)
वास्तव में हमें IdentityDbContext से विरासत में प्राप्त करने की आवश्यकता नहीं है यदि हम सभी कोड स्वयं लिखते हैं।
इसलिए मूल रूप से हम सिर्फ DbContext से विरासत में प्राप्त कर सकते हैं और IdentityDbContext स्रोत कोड से "OnModelCreating (ModelBuilder बिल्डर)" ​​के हमारे अनुकूलित संस्करण को लागू कर सकते हैं।


2
@ माइक-डेवेनी यहाँ दो संदर्भ परतों के विलय के बारे में आपका जवाब है, आशा है कि यह मदद करता है।
अरविंद

1
धन्यवाद अरवंद, मुझे यह याद आया और फिर से विषय को देखते हुए 1.5 साल बाद यह काफी अजीब तरह से वापस आ गया। :)
माइक Devenney

9

यह लोगों के लिए देर से प्रविष्टि है, लेकिन नीचे मेरा कार्यान्वयन है। आप यह भी देखेंगे कि मैंने स्टब्स-आउट करने की क्षमता बदल दी है डिफ़ॉल्ट डिफ़ॉल्ट प्रकार: जिसके बारे में विवरण निम्नलिखित लेखों में पाया जा सकता है:

नोट:
यह ध्यान दिया जाना चाहिए कि आप Guid'sअपनी कुंजी के लिए उपयोग नहीं कर सकते । ऐसा इसलिए है क्योंकि हुड के तहत वे एक हैं Struct, और इस तरह, कोई अनबॉक्सिंग नहीं है जो सामान्य <TKey>पैरामीटर से उनके रूपांतरण की अनुमति देगा ।

क्लास की तरह देखो:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, string, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
    #region <Constructors>

    public ApplicationDbContext() : base(Settings.ConnectionString.Database.AdministrativeAccess)
    {
    }

    #endregion

    #region <Properties>

    //public DbSet<Case> Case { get; set; }

    #endregion

    #region <Methods>

    #region

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        //modelBuilder.Configurations.Add(new ResourceConfiguration());
        //modelBuilder.Configurations.Add(new OperationsToRolesConfiguration());
    }

    #endregion

    #region

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    #endregion

    #endregion
}

    public class ApplicationUser : IdentityUser<string, CustomUserLogin, CustomUserRole, CustomUserClaim>
    {
        #region <Constructors>

        public ApplicationUser()
        {
            Init();
        }

        #endregion

        #region <Properties>

        [Required]
        [StringLength(250)]
        public string FirstName { get; set; }

        [Required]
        [StringLength(250)]
        public string LastName { get; set; }

        #endregion

        #region <Methods>

        #region private

        private void Init()
        {
            Id = Guid.Empty.ToString();
        }

        #endregion

        #region public

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, string> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);

            // Add custom user claims here

            return userIdentity;
        }

        #endregion

        #endregion
    }

    public class CustomUserStore : UserStore<ApplicationUser, CustomRole, string, CustomUserLogin, CustomUserRole, CustomUserClaim>
    {
        #region <Constructors>

        public CustomUserStore(ApplicationDbContext context) : base(context)
        {
        }

        #endregion
    }

    public class CustomUserRole : IdentityUserRole<string>
    {
    }

    public class CustomUserLogin : IdentityUserLogin<string>
    {
    }

    public class CustomUserClaim : IdentityUserClaim<string> 
    { 
    }

    public class CustomRoleStore : RoleStore<CustomRole, string, CustomUserRole>
    {
        #region <Constructors>

        public CustomRoleStore(ApplicationDbContext context) : base(context)
        {
        } 

        #endregion
    }

    public class CustomRole : IdentityRole<string, CustomUserRole>
    {
        #region <Constructors>

        public CustomRole() { }
        public CustomRole(string name) 
        { 
            Name = name; 
        }

        #endregion
    }

8

यदि आप IdentityDbContext के सार के माध्यम से नीचे आते हैं, तो आप पाएंगे कि यह आपके व्युत्पन्न DbContext की तरह दिखता है। सबसे आसान मार्ग ओलाव का उत्तर है, लेकिन यदि आप चाहते हैं कि क्या बनाया जा रहा है और अधिक नियंत्रण चाहते हैं, तो आइडेंटिटी पैकेज पर थोड़ी कम निर्भरता मेरे प्रश्न और उत्तर पर एक नज़र डालती है । यदि आप लिंक का अनुसरण करते हैं तो एक कोड उदाहरण है, लेकिन सारांश में आप बस अपने स्वयं के DbContext उपवर्ग में आवश्यक DbSets जोड़ते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.