Add Store.MaxLengthForKeys (#1555)
* Add Store.MaxLengthForKeys If set this will set max length of things we use for composite keys in UserTokens/Logins Needed for https://github.com/aspnet/templating/issues/62
This commit is contained in:
parent
85f8a49aef
commit
b07a95dd09
|
|
@ -32,7 +32,7 @@ namespace IdentitySample.DefaultUI
|
||||||
options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
|
options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
|
||||||
x => x.MigrationsAssembly("IdentitySample.DefaultUI")));
|
x => x.MigrationsAssembly("IdentitySample.DefaultUI")));
|
||||||
|
|
||||||
services.AddIdentity<IdentityUser, IdentityRole>()
|
services.AddIdentity<IdentityUser, IdentityRole>(o => o.Stores.MaxLengthForKeys = 128)
|
||||||
.AddEntityFrameworkStores<IdentityDbContext>()
|
.AddEntityFrameworkStores<IdentityDbContext>()
|
||||||
.AddDefaultUI()
|
.AddDefaultUI()
|
||||||
.AddDefaultTokenProviders();
|
.AddDefaultTokenProviders();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=Interop-Shared-10-10;Trusted_Connection=True;MultipleActiveResultSets=true"
|
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=IdentitySample-MVC-1-10;Trusted_Connection=True;MultipleActiveResultSets=true"
|
||||||
},
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"IncludeScopes": false,
|
"IncludeScopes": false,
|
||||||
|
|
|
||||||
|
|
@ -55,5 +55,13 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
/// The <see cref="TokenOptions"/> for the identity system.
|
/// The <see cref="TokenOptions"/> for the identity system.
|
||||||
/// </value>
|
/// </value>
|
||||||
public TokenOptions Tokens { get; set; } = new TokenOptions();
|
public TokenOptions Tokens { get; set; } = new TokenOptions();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="StoreOptions"/> for the identity system.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The <see cref="StoreOptions"/> for the identity system.
|
||||||
|
/// </value>
|
||||||
|
public StoreOptions Stores { get; set; } = new StoreOptions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used for store specific options
|
||||||
|
/// </summary>
|
||||||
|
public class StoreOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// If set to a positive number, the default OnModelCreating will use this value as the max length for any
|
||||||
|
/// properties used as keys, i.e. UserId, LoginProvider, ProviderKey.
|
||||||
|
/// </summary>
|
||||||
|
public int MaxLengthForKeys { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,12 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
|
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
|
||||||
{
|
{
|
||||||
|
|
@ -91,6 +96,18 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DbSet<TUserToken> UserTokens { get; set; }
|
public DbSet<TUserToken> UserTokens { get; set; }
|
||||||
|
|
||||||
|
private int GetMaxLengthForKeys()
|
||||||
|
{
|
||||||
|
// Need to get the actual application service provider, fallback will cause
|
||||||
|
// options to not work since IEnumerable<IConfigureOptions> don't flow across providers
|
||||||
|
var options = this.GetService<IDbContextOptions>()
|
||||||
|
.Extensions.OfType<CoreOptionsExtension>()
|
||||||
|
.FirstOrDefault()?.ApplicationServiceProvider
|
||||||
|
?.GetService<IOptions<IdentityOptions>>()
|
||||||
|
?.Value?.Stores;
|
||||||
|
return options != null ? options.MaxLengthForKeys : 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the schema needed for the identity framework.
|
/// Configures the schema needed for the identity framework.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -99,6 +116,8 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
|
||||||
/// </param>
|
/// </param>
|
||||||
protected override void OnModelCreating(ModelBuilder builder)
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
{
|
{
|
||||||
|
var maxKeyLength = GetMaxLengthForKeys();
|
||||||
|
|
||||||
builder.Entity<TUser>(b =>
|
builder.Entity<TUser>(b =>
|
||||||
{
|
{
|
||||||
b.HasKey(u => u.Id);
|
b.HasKey(u => u.Id);
|
||||||
|
|
@ -112,7 +131,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
|
||||||
b.Property(u => u.Email).HasMaxLength(256);
|
b.Property(u => u.Email).HasMaxLength(256);
|
||||||
b.Property(u => u.NormalizedEmail).HasMaxLength(256);
|
b.Property(u => u.NormalizedEmail).HasMaxLength(256);
|
||||||
|
|
||||||
// Replace with b.HasMany<IdentityUserClaim>().
|
|
||||||
b.HasMany<TUserClaim>().WithOne().HasForeignKey(uc => uc.UserId).IsRequired();
|
b.HasMany<TUserClaim>().WithOne().HasForeignKey(uc => uc.UserId).IsRequired();
|
||||||
b.HasMany<TUserLogin>().WithOne().HasForeignKey(ul => ul.UserId).IsRequired();
|
b.HasMany<TUserLogin>().WithOne().HasForeignKey(ul => ul.UserId).IsRequired();
|
||||||
b.HasMany<TUserToken>().WithOne().HasForeignKey(ut => ut.UserId).IsRequired();
|
b.HasMany<TUserToken>().WithOne().HasForeignKey(ut => ut.UserId).IsRequired();
|
||||||
|
|
@ -127,12 +145,26 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
|
||||||
builder.Entity<TUserLogin>(b =>
|
builder.Entity<TUserLogin>(b =>
|
||||||
{
|
{
|
||||||
b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
|
b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
|
||||||
|
|
||||||
|
if (maxKeyLength > 0)
|
||||||
|
{
|
||||||
|
b.Property(l => l.LoginProvider).HasMaxLength(maxKeyLength);
|
||||||
|
b.Property(l => l.ProviderKey).HasMaxLength(maxKeyLength);
|
||||||
|
}
|
||||||
|
|
||||||
b.ToTable("AspNetUserLogins");
|
b.ToTable("AspNetUserLogins");
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Entity<TUserToken>(b =>
|
builder.Entity<TUserToken>(b =>
|
||||||
{
|
{
|
||||||
b.HasKey(l => new { l.UserId, l.LoginProvider, l.Name });
|
b.HasKey(t => new { t.UserId, t.LoginProvider, t.Name });
|
||||||
|
|
||||||
|
if (maxKeyLength > 0)
|
||||||
|
{
|
||||||
|
b.Property(t => t.LoginProvider).HasMaxLength(maxKeyLength);
|
||||||
|
b.Property(t => t.Name).HasMaxLength(maxKeyLength);
|
||||||
|
}
|
||||||
|
|
||||||
b.ToTable("AspNetUserTokens");
|
b.ToTable("AspNetUserTokens");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,16 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using System.Data.SqlClient;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
|
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
|
||||||
{
|
{
|
||||||
public static class DbUtil
|
public static class DbUtil
|
||||||
{
|
{
|
||||||
public static IServiceCollection ConfigureDbServices(string connectionString, IServiceCollection services = null)
|
|
||||||
{
|
|
||||||
return ConfigureDbServices<IdentityDbContext>(connectionString, services);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IServiceCollection ConfigureDbServices<TContext>(string connectionString, IServiceCollection services = null) where TContext : DbContext
|
public static IServiceCollection ConfigureDbServices<TContext>(string connectionString, IServiceCollection services = null) where TContext : DbContext
|
||||||
{
|
{
|
||||||
if (services == null)
|
if (services == null)
|
||||||
|
|
@ -21,7 +18,10 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
|
||||||
services = new ServiceCollection();
|
services = new ServiceCollection();
|
||||||
}
|
}
|
||||||
services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
services.AddDbContext<TContext>(options => options.UseSqlServer(connectionString));
|
services.AddDbContext<TContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseSqlServer(connectionString);
|
||||||
|
});
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,5 +30,74 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
|
||||||
var serviceProvider = ConfigureDbServices<TContext>(connectionString).BuildServiceProvider();
|
var serviceProvider = ConfigureDbServices<TContext>(connectionString).BuildServiceProvider();
|
||||||
return serviceProvider.GetRequiredService<TContext>();
|
return serviceProvider.GetRequiredService<TContext>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool VerifyMaxLength(SqlConnection conn, string table, int maxLength, params string[] columns)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
using (
|
||||||
|
var command =
|
||||||
|
new SqlCommand("SELECT COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@Table", conn))
|
||||||
|
{
|
||||||
|
command.Parameters.Add(new SqlParameter("Table", table));
|
||||||
|
using (var reader = command.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (!columns.Contains(reader.GetString(0)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (reader.GetInt32(1) != maxLength)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count == columns.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool VerifyColumns(SqlConnection conn, string table, params string[] columns)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
using (
|
||||||
|
var command =
|
||||||
|
new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@Table", conn))
|
||||||
|
{
|
||||||
|
command.Parameters.Add(new SqlParameter("Table", table));
|
||||||
|
using (var reader = command.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
if (!columns.Contains(reader.GetString(0)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == columns.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void VerifyIndex(SqlConnection conn, string table, string index, bool isUnique = false)
|
||||||
|
{
|
||||||
|
using (
|
||||||
|
var command =
|
||||||
|
new SqlCommand(
|
||||||
|
"SELECT COUNT(*) FROM sys.indexes where NAME=@Index AND object_id = OBJECT_ID(@Table) AND is_unique = @Unique", conn))
|
||||||
|
{
|
||||||
|
command.Parameters.Add(new SqlParameter("Index", index));
|
||||||
|
command.Parameters.Add(new SqlParameter("Table", table));
|
||||||
|
command.Parameters.Add(new SqlParameter("Unique", isUnique));
|
||||||
|
using (var reader = command.ExecuteReader())
|
||||||
|
{
|
||||||
|
Assert.True(reader.Read());
|
||||||
|
Assert.True(reader.GetInt32(0) > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using Microsoft.AspNetCore.Builder.Internal;
|
||||||
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
|
||||||
|
{
|
||||||
|
public class MaxKeyLengthSchemaTest : IClassFixture<ScratchDatabaseFixture>
|
||||||
|
{
|
||||||
|
private readonly ApplicationBuilder _builder;
|
||||||
|
private const string DatabaseName = nameof(MaxKeyLengthSchemaTest);
|
||||||
|
|
||||||
|
public MaxKeyLengthSchemaTest(ScratchDatabaseFixture fixture)
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build())
|
||||||
|
.AddDbContext<IdentityDbContext>(o => o.UseSqlServer(fixture.ConnectionString))
|
||||||
|
.AddIdentity<IdentityUser, IdentityRole>(o => o.Stores.MaxLengthForKeys = 128)
|
||||||
|
.AddEntityFrameworkStores<IdentityDbContext>();
|
||||||
|
|
||||||
|
services.AddLogging();
|
||||||
|
|
||||||
|
var provider = services.BuildServiceProvider();
|
||||||
|
_builder = new ApplicationBuilder(provider);
|
||||||
|
|
||||||
|
using (var scoped = provider.GetRequiredService<IServiceScopeFactory>().CreateScope())
|
||||||
|
using (var db = scoped.ServiceProvider.GetRequiredService<IdentityDbContext>())
|
||||||
|
{
|
||||||
|
db.Database.EnsureCreated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||||
|
[OSSkipCondition(OperatingSystems.Linux)]
|
||||||
|
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||||
|
public void EnsureDefaultSchema()
|
||||||
|
{
|
||||||
|
var db = _builder.ApplicationServices.GetRequiredService<IdentityDbContext>();
|
||||||
|
VerifyDefaultSchema(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void VerifyDefaultSchema(IdentityDbContext dbContext)
|
||||||
|
{
|
||||||
|
var sqlConn = dbContext.Database.GetDbConnection();
|
||||||
|
|
||||||
|
using (var db = new SqlConnection(sqlConn.ConnectionString))
|
||||||
|
{
|
||||||
|
db.Open();
|
||||||
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUsers", "Id", "UserName", "Email", "PasswordHash", "SecurityStamp",
|
||||||
|
"EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled",
|
||||||
|
"LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail"));
|
||||||
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetRoles", "Id", "Name", "NormalizedName", "ConcurrencyStamp"));
|
||||||
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserRoles", "UserId", "RoleId"));
|
||||||
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserClaims", "Id", "UserId", "ClaimType", "ClaimValue"));
|
||||||
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName"));
|
||||||
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserTokens", "UserId", "LoginProvider", "Name", "Value"));
|
||||||
|
|
||||||
|
Assert.True(DbUtil.VerifyMaxLength(db, "AspNetUsers", 256, "UserName", "Email", "NormalizedUserName", "NormalizedEmail"));
|
||||||
|
Assert.True(DbUtil.VerifyMaxLength(db, "AspNetRoles", 256, "Name", "NormalizedName"));
|
||||||
|
Assert.True(DbUtil.VerifyMaxLength(db, "AspNetUserLogins", 128, "LoginProvider", "ProviderKey"));
|
||||||
|
Assert.True(DbUtil.VerifyMaxLength(db, "AspNetUserTokens", 128, "LoginProvider", "Name"));
|
||||||
|
|
||||||
|
DbUtil.VerifyIndex(db, "AspNetRoles", "RoleNameIndex", isUnique: true);
|
||||||
|
DbUtil.VerifyIndex(db, "AspNetUsers", "UserNameIndex", isUnique: true);
|
||||||
|
DbUtil.VerifyIndex(db, "AspNetUsers", "EmailIndex");
|
||||||
|
db.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -92,62 +92,24 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
|
||||||
using (var db = new SqlConnection(sqlConn.ConnectionString))
|
using (var db = new SqlConnection(sqlConn.ConnectionString))
|
||||||
{
|
{
|
||||||
db.Open();
|
db.Open();
|
||||||
Assert.True(VerifyColumns(db, "AspNetUsers", "Id", "UserName", "Email", "PasswordHash", "SecurityStamp",
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUsers", "Id", "UserName", "Email", "PasswordHash", "SecurityStamp",
|
||||||
"EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled",
|
"EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled",
|
||||||
"LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail"));
|
"LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail"));
|
||||||
Assert.False(VerifyColumns(db, "AspNetRoles", "Id", "Name", "NormalizedName", "ConcurrencyStamp"));
|
Assert.False(DbUtil.VerifyColumns(db, "AspNetRoles", "Id", "Name", "NormalizedName", "ConcurrencyStamp"));
|
||||||
Assert.False(VerifyColumns(db, "AspNetUserRoles", "UserId", "RoleId"));
|
Assert.False(DbUtil.VerifyColumns(db, "AspNetUserRoles", "UserId", "RoleId"));
|
||||||
Assert.True(VerifyColumns(db, "AspNetUserClaims", "Id", "UserId", "ClaimType", "ClaimValue"));
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserClaims", "Id", "UserId", "ClaimType", "ClaimValue"));
|
||||||
Assert.True(VerifyColumns(db, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName"));
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName"));
|
||||||
Assert.True(VerifyColumns(db, "AspNetUserTokens", "UserId", "LoginProvider", "Name", "Value"));
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserTokens", "UserId", "LoginProvider", "Name", "Value"));
|
||||||
|
|
||||||
|
DbUtil.VerifyIndex(db, "AspNetUsers", "UserNameIndex", isUnique: true);
|
||||||
|
DbUtil.VerifyIndex(db, "AspNetUsers", "EmailIndex");
|
||||||
|
|
||||||
|
DbUtil.VerifyMaxLength(db, "AspNetUsers", 256, "UserName", "Email", "NormalizeUserName", "NormalizeEmail");
|
||||||
|
|
||||||
VerifyIndex(db, "AspNetUsers", "UserNameIndex", isUnique: true);
|
|
||||||
VerifyIndex(db, "AspNetUsers", "EmailIndex");
|
|
||||||
db.Close();
|
db.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool VerifyColumns(SqlConnection conn, string table, params string[] columns)
|
|
||||||
{
|
|
||||||
var count = 0;
|
|
||||||
using (
|
|
||||||
var command =
|
|
||||||
new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@Table", conn))
|
|
||||||
{
|
|
||||||
command.Parameters.Add(new SqlParameter("Table", table));
|
|
||||||
using (var reader = command.ExecuteReader())
|
|
||||||
{
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
if (!columns.Contains(reader.GetString(0)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count == columns.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void VerifyIndex(SqlConnection conn, string table, string index, bool isUnique = false)
|
|
||||||
{
|
|
||||||
using (
|
|
||||||
var command =
|
|
||||||
new SqlCommand(
|
|
||||||
"SELECT COUNT(*) FROM sys.indexes where NAME=@Index AND object_id = OBJECT_ID(@Table) AND is_unique = @Unique", conn))
|
|
||||||
{
|
|
||||||
command.Parameters.Add(new SqlParameter("Index", index));
|
|
||||||
command.Parameters.Add(new SqlParameter("Table", table));
|
|
||||||
command.Parameters.Add(new SqlParameter("Unique", isUnique));
|
|
||||||
using (var reader = command.ExecuteReader())
|
|
||||||
{
|
|
||||||
Assert.True(reader.Read());
|
|
||||||
Assert.True(reader.GetInt32(0) > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||||
[OSSkipCondition(OperatingSystems.Linux)]
|
[OSSkipCondition(OperatingSystems.Linux)]
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Identity.Test;
|
using Microsoft.AspNetCore.Identity.Test;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
|
@ -130,63 +129,25 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
|
||||||
using (var db = new SqlConnection(sqlConn.ConnectionString))
|
using (var db = new SqlConnection(sqlConn.ConnectionString))
|
||||||
{
|
{
|
||||||
db.Open();
|
db.Open();
|
||||||
Assert.True(VerifyColumns(db, "AspNetUsers", "Id", "UserName", "Email", "PasswordHash", "SecurityStamp",
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUsers", "Id", "UserName", "Email", "PasswordHash", "SecurityStamp",
|
||||||
"EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled",
|
"EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled",
|
||||||
"LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail"));
|
"LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail"));
|
||||||
Assert.True(VerifyColumns(db, "AspNetRoles", "Id", "Name", "NormalizedName", "ConcurrencyStamp"));
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetRoles", "Id", "Name", "NormalizedName", "ConcurrencyStamp"));
|
||||||
Assert.True(VerifyColumns(db, "AspNetUserRoles", "UserId", "RoleId"));
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserRoles", "UserId", "RoleId"));
|
||||||
Assert.True(VerifyColumns(db, "AspNetUserClaims", "Id", "UserId", "ClaimType", "ClaimValue"));
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserClaims", "Id", "UserId", "ClaimType", "ClaimValue"));
|
||||||
Assert.True(VerifyColumns(db, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName"));
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName"));
|
||||||
Assert.True(VerifyColumns(db, "AspNetUserTokens", "UserId", "LoginProvider", "Name", "Value"));
|
Assert.True(DbUtil.VerifyColumns(db, "AspNetUserTokens", "UserId", "LoginProvider", "Name", "Value"));
|
||||||
|
|
||||||
VerifyIndex(db, "AspNetRoles", "RoleNameIndex", isUnique: true);
|
Assert.True(DbUtil.VerifyMaxLength(db, "AspNetUsers", 256, "UserName", "Email", "NormalizedUserName", "NormalizedEmail"));
|
||||||
VerifyIndex(db, "AspNetUsers", "UserNameIndex", isUnique: true);
|
Assert.True(DbUtil.VerifyMaxLength(db, "AspNetRoles", 256, "Name", "NormalizedName"));
|
||||||
VerifyIndex(db, "AspNetUsers", "EmailIndex");
|
|
||||||
|
DbUtil.VerifyIndex(db, "AspNetRoles", "RoleNameIndex", isUnique: true);
|
||||||
|
DbUtil.VerifyIndex(db, "AspNetUsers", "UserNameIndex", isUnique: true);
|
||||||
|
DbUtil.VerifyIndex(db, "AspNetUsers", "EmailIndex");
|
||||||
db.Close();
|
db.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool VerifyColumns(SqlConnection conn, string table, params string[] columns)
|
|
||||||
{
|
|
||||||
var count = 0;
|
|
||||||
using (
|
|
||||||
var command =
|
|
||||||
new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@Table", conn))
|
|
||||||
{
|
|
||||||
command.Parameters.Add(new SqlParameter("Table", table));
|
|
||||||
using (var reader = command.ExecuteReader())
|
|
||||||
{
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
if (!columns.Contains(reader.GetString(0)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count == columns.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void VerifyIndex(SqlConnection conn, string table, string index, bool isUnique = false)
|
|
||||||
{
|
|
||||||
using (
|
|
||||||
var command =
|
|
||||||
new SqlCommand(
|
|
||||||
"SELECT COUNT(*) FROM sys.indexes where NAME=@Index AND object_id = OBJECT_ID(@Table) AND is_unique = @Unique", conn))
|
|
||||||
{
|
|
||||||
command.Parameters.Add(new SqlParameter("Index", index));
|
|
||||||
command.Parameters.Add(new SqlParameter("Table", table));
|
|
||||||
command.Parameters.Add(new SqlParameter("Unique", isUnique));
|
|
||||||
using (var reader = command.ExecuteReader())
|
|
||||||
{
|
|
||||||
Assert.True(reader.Read());
|
|
||||||
Assert.True(reader.GetInt32(0) > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||||
[OSSkipCondition(OperatingSystems.Linux)]
|
[OSSkipCondition(OperatingSystems.Linux)]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue