How to add new colum into Identity RoleClaims table (asp net core) - asp.net-core

I'm trying to add a column to the identity (asp net core) RoleClaims table but I find content just to extend the roles and users classes and not to RoleClaims.
Could someone help with examples or point out content.

You would need to create a new class to extend the RoleClaim. Here is an example of how to do it if your key type is string:
public class ApplicationRoleClaim : IdentityRoleClaim<string>
{
public virtual ApplicationRole Role { get; set; }
}
You can add whatever new properties you want to this class then create a migration to add them as table columns.
You would also need to tell your IdentityDbContext to use this new class as well. Here is an example from the docs:
public class ApplicationDbContext
: IdentityDbContext<
ApplicationUser, ApplicationRole, string,
ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin,
ApplicationRoleClaim, ApplicationUserToken>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
EDIT:
With your custom ApplicationRoleClaim class, you could override OnModelCreating as well. This is an example from the docs:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
⋮
modelBuilder.Entity<IdentityRoleClaim<string>>(b =>
{
b.ToTable("MyRoleClaims");
});
⋮
}
Reference: Identity model customization in ASP.NET Core

I made a demo with asp.net core 2.2 and it worked well ,try the following code , customize ApplicationRoleClaim to add other propertyies.
public class ApplicationRoleClaim: IdentityRoleClaim<string>
{
public string Description { get; set; }
}
Then use DbSet<TEntity> class which represents a collection for a given entity within the model and is the gateway to database operations against an entity to add the new column to table
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<ApplicationRoleClaim> ApplicationRoleClaim { get; set; }
}
Finally add-migration and update-database.

Related

Migration Issue AspNetCore API

I am working on a project in which I am using the code-first approach to add migration of my existing entities. I am facing the following related issue shown in the image.
Here is my dbContext class
public class LicenseDbContext: IdentityDbContext<LicenseUser, LicenseUserRole, long>
{
public LicenseDbContext(
DbContextOptions<LicenseDbContext> options
) : base(options)
{
}
}
Here is are License User and LicenseUserRole classes
public class LicenseUser : IdentityUser<long>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public ApplicationRoleEnum UserRole { get; set; }
}
public class LicenseUserRole : IdentityRole<long>
{
public LicenseUserRole() : base()
{
}
public LicenseUserRole(string roleName) : base(roleName)
{
}
}
I am using EF Core version 5.0.9. It always says installation of both EF6 and EFCore though I have installed only Core.
An error occurred while accessing the Microsoft.Extensions.Hosting services. Continuing without the application service provider. Error: GenericArguments[1], 'Microsoft.AspNetCore.Identity.IdentityRole', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9[TUser,TRole,TContext,TKey,TUserClaim,TUserRole,TUserLogin,TUserToken,TRoleClaim]' violates the constraint of type 'TRole'.
For this issue, I can reproduce it when I register wrong IdentityRole.
Be sure register your service like below:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<LicenseDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<LicenseUser, LicenseUserRole>(options => options.SignIn.RequireConfirmedAccount = false)
.AddEntityFrameworkStores<LicenseDbContext>();
//other services...
}

OnModelCreating code refactoring from EF6 to EF core 3.1

I am trying to refactor the OnModelCreating method before when it used to be a part of ASP.net: :
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Types().Configure(c => c.ToTable(c.ClrType.Name.ToUpper()));
modelBuilder.Properties().Configure(c => c.HasColumnName(c.ClrPropertyInfo.Name.ToUpper()));
....
But now after migrating to .netCore 3.1 I am getting this error
'ModelBuilder' does not contain a definition for 'Types' and no accessible extension method 'Types' accepting a first argument of type 'ModelBuilder' could be found
Could you please suggest a way to refactor the code properly while keeping the same old logic
Thanks for your help
According to your code, it seems that you want to change the Table Name and set the Column Name, if that is the case, you could try to refer the following code to override the OnModelCreating method:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Write Fluent API configurations here
//Property Configurations
modelBuilder.Entity<Blog>().ToTable("BLOGS");
modelBuilder.Entity<Blog>()
.Property(b => b.BlogId)
.HasColumnName("BLOG_ID");
}
}
More detail information, please check the following links:
EF Core Fluent API Configuration
Entity Types # Table Name
Column names
How to Specify Entity Framework Core Table Mapping?
Edit:
And what about the second config rule ;
modelBuilder.Properties().Configure(c =>
c.HasColumnName(c.ClrPropertyInfo.Name.ToUpper())); I cant go through
every column there to just make it uppercase
There have an open source plugin (Naming Conventions) which might help you. By using its UseUpperCaseNamingConvention, it could change the table and Column name to Uppercase.
You could refer to the following steps to use it:
Add the EFCore.NamingConventions from the Nuget.
Enable the naming convention in your model's OnConfiguring method:
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.EnableSensitiveDataLogging();
optionsBuilder
.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true") //database connection string.
.UseUpperCaseNamingConvention();
}
}
After migration, you can see the Model Snapshot, it will change the Table and Column name as below:
Then, after update the database, the table like this:
[Note] The Naming Conventions is a community-maintained plugin: it isn't an official part of Entity Framework Core and isn't supported by Microsoft in any way.

Entity Framework Core Issue - Update-Database Creating "User" Schemas

I've been working for quite a while on a production application using .NET Core 2.0 (originally 1.0) & EF Core.
This is a Code-First designed application, so all database changes have been made via Migrations.
Up until a recent deployment, Update-Database would make the changes correctly - however, recently it has been creating new schemas each time a model is added (instead of adding to the dbo schema like normal).
Example:
New Class Model: Test.cs
Table created in Database: DOMAIN\CurrentUser.Test
Any ideas on why this would be happening?
I suppose I can dig deep into the migrationBuilder to figure out how it is making Schema decisions, but seems like something simple must have changed to change the behavior.
"DOMAIN\CurrentUser" has dbo rights on the server in question.
For changing schema from EF Core, try to configure with builder.HasDefaultSchema("newschema"); or builder.Entity<User>().ToTable.
For changing the schema for all tables.
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<User> User { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.HasDefaultSchema("newschema");
}
}
For chaning the schema for specific table.
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<User> User { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<User>().ToTable("User", "newSchema");
}
}

Creating a database context using the database first approach with entityframework core.

I want to be able to create a database context with entityframework core in my webapi project using the database first approach.
When I create like this it works very well
public class TestingContext : DbContext
{
public TestingContext(DbContextOptions<TestingContext> options)
: base(options)
{
}
public TestingContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=xxxxxx;Initial Catalog=xxxxxx;Integrated Security=False;User Id=xxxxx;Password=xxxxx;MultipleActiveResultSets=True");
}
public DbSet<Information> Information { get; set; }
public DbSet<ArticleUser> ArticleUser { get; set; }
}
I had to add the line services.AddDbContext to make it work.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddCors();
//using Dependency Injection
services.AddSingleton<Ixxx, xxx>();
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddDbContext<TestingContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "Articles API", Version = "v1" });
});
}
If I remove this method from my TestingContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=xxxxxx;Initial Catalog=xxxxxx;Integrated Security=False;User Id=xxxxx;Password=xxxxx;MultipleActiveResultSets=True");
}
I get the error below.
No database provider has been configured for this DbContext.
A provider can be configured by overriding the DbContext.OnConfiguring method or
by using AddDbContext on the application service provider. If AddDbContext is used,
then also ensure that your DbContext type accepts a DbContextOptions object in its
constructor and passes it to the base constructor for DbContext.
Why do I need to pass my connection string to the database in two places before it can pull my data. Please assist. I am new to the core. The two places are configure services method and the context itself.
Option 1: Remove parameterized constructor and OnConfiguring. Result:
public class TestingContext : DbContext
{
public DbSet<Information> Information { get; set; }
public DbSet<ArticleUser> ArticleUser { get; set; }
}
Option 2: Remove parameterized constructor and options in ConfigureServices in AddDbContext
Result:
In Startup.cs
services.AddDbContext<TestingContext>();
In TestingDbContext.cs
public class TestingDdContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=xxxxxx;Initial Catalog=xxxxxx;Integrated Security=False;User Id=xxxxx;Password=xxxxx;MultipleActiveResultSets=True");
}
public DbSet<Information> Information { get; set; }
public DbSet<ArticleUser> ArticleUser { get; set; }
}
Option 3: A parametric constructor is needed to create factory. Example:
public class TestDdContext : DbContext
{
public TestDdContext(DbContextOptions options) : base(options)
{
}
//TODO: DbSets
}
public class TestDbContextFactory : IDbContextFactory<TestDdContext>
{
public TestDdContext Create(DbContextFactoryOptions options)
{
var contextOptions = new DbContextOptionsBuilder();
contextOptions.UseSqlServer("...");
return new TestDdContext(contextOptions.Options);
}
}
If you are creating tests, do you need a backing Sql database? Would the In-memory provider not serve you better?
options.UseInMemoryDatabase("database-name");
For this reason, I'd ditch using the OnConfiguring method, and rely on passing the DbContextOptions to your constructor
Side note, you have to consider what you are testing - are you testing your code that is dependent on your DbContext, or are you testing your DbContext itself - if there is no custom logic and you are merely extending the DbContext, there may not be enough value in writing tests for it - and you're not responsible for testing EFCore itself.

How to implement custom role based authorization in ASP.Net MVC

I am working on a project where we are using Amazon SimpleDB as a data storage. In this application user can create roles at run time. While creating role, user can give Read/Write/Update permission for specific feature.
The code I have tried;
using System;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MyAuthorization : ActionFilterAttribute
{
public string Model { get; set; }
public string Action { get; set; }
public override void OnActionExecuting(HttpActionContext filterContext)
{
//My code will go here
base.OnActionExecuting(filterContext);
}
}
In Web API controller I have written as;
// GET api/values
[MyAuthorization(Action = "Edit", Model = "Rack")]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
Now in OnActionExecuting, I want to fetch Action and Model attributes which I have specified over action method in APIController.
How to handle it through code, since role names and rights are not known at design time.
I assume that each feature you will be implementing in a certain controller and each action method designates the type of operation you are performing (ex Read, Write etc).
If my assumption is correct, you may have to first extend the AuthorzeAttribute ASP.NET MVC framework like below.
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public string Operation;
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
//Get the User Id from the session
// Get Role associated with the user (probably from database)
// get the permission associated with the role (like Read, write etc)
// Let assume the retrieved operations are in the form of list of strings
List<string> retrievedOperations =RetrieveRoleOperations(userId)
if (!retrievedOperations.Contains(Operation)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
After creating this class, you have to specify the extended authorize filter in required action methods like below.
Class MyFeatureController:Controller
{
[MyCustomAuthorize(Operation="Read")]
public ActionResult MyReadMethod()
{
//
}
}
I hope this will solve your problem.