Add custom column in AspNetRoles results in Invalid Column Name Discriminator - asp.net-mvc

I'm using ASP.NET MVC5 with Identity 2 framework, Database first
I'm trying to custom AspNetRoles, by adding a column called MyCustomColumn
However, my app crashes because :
Invalid Column Name Discriminator
There is a lot of resources on SO and elsewhere on the web, but most of them are with CodeFirst approach and I can't use them in my app.
How to deal with it ?

Actually, none of this is necessary. Most likely you failed to update your context to inherit from IdentityDbContext<TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim>, rather than the default of IdentityDbContext<TUser>. Since you did not pass your custom role entity as the TRole type parameter, the context instead uses IdentityRole as the class type. It then creates a table for IdentityRole, sees that your custom role inherits from IdentityRole, and therefore adds the Discriminator column so that it can tell the different between an instance of IdentityRole and your custom role, in the database (single table inheritance is the default strategy EF employs).
This will technically work, but your custom role will never actually be utilized. Use the right generic abstract context class, and you'll be fine.
For what it's worth, you should do away with the EDMX stuff, as well. It's deprecated, buggy, and unnecessary. Despite the name, "Code First" can be used with an existing database or to create a new one.
DON'T
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
DO
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>

Ok, as I spend some hours to find a solution, I post it here, if it could help someone else.
First, in AspNetRoles, create your custom column AND a column called Discriminator (which is a nvarchar(max) ). Update your .edmx
Then, we have to create a class which inherits from IdentityRole. We will use this class to access our custom column we just created :
In Models folder
public ApplicationRole()
: base() { }
public ApplicationRole(string name, long myCustomValue)
: base(name)
{
MyCustomValue = myCustomValue;
}
public virtual long MyCustomValue { get; set; }
Then, let's create a class which inherits from RoleManager<ApplicationRole>.
I placed it in IdentityConfig.cs, but maybe it's a best practice to place it elsewhere...
For information, I get inspired by this blog, Re-Implementing RoleStore and ApplicationRoleManager paragraph
public class ApplicationRoleManager : RoleManager<ApplicationRole>
{
public ApplicationRoleManager(
IRoleStore<ApplicationRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(
IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(
new RoleStore<ApplicationRole>(context.Get<ApplicationDbContext>()));
}
}
ApplicationRoleManager has a constructor which calls our previously created ApplicationRole class.
Now we have to register our ApplicationRoleManager at startup, so we have to add this line after the others CreatePerOwinContext
In App_Start\Startup.auth.cs, ConfigureAuth(IAppBuilder app) method
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
So now we can use our ApplicationRoleManager, correctly instanciated :
var rm = new ApplicationRoleManager(new RoleStore<ApplicationRole>(new ApplicationDbContext()));
And then use it as we want
var roleName = rm.FindByName("Admin");
string myCustomData = roleName.CustomData.ToString();

Related

How can I code a method for reuse when the critical parameter is a EF DbContext?

I have 4 different SQL databases that hold similar data; they’re all based off the same model. They differ according to version of the data, where they're being used, etc.
Db1Context
Db2Context
Db3Context
Db4Context
Upon initialization, I need to make sure each of the databases have a single parent record, so I run a method that looks something like this:
Sub EnsureATableExists()
Dim theDb = New Db1Context
Dim parentTable = theDb.parentTables.Where(Function(x) x.somedata = "somedata").FirstOrDefault()
If parentTable Is Nothing Then
parentTable = CreateTable()
theDb.parentTables.Add(parentTable)
theDb.SaveChanges()
End If
End Sub
But I currently have 4 of these methods which offends my sense of DRY. But I don’t how to write this method for reuse because the declaration of a DbContext is unique and I can’t really parametrize the DbContext to hand in.
I assume there is some common technique for coding this and would appreciate being taught.
Additional code added per comment below:
This is my current context. It is repeated 3 more times with the different names like listed above and respective connection strings.
I converted my vb.net to C# and believe I'll be able to convert any examples provided back into vb.net.
public class Db1Context : DbContext
{
public Db1Context() : base("Db1Connection")
{
}
public Db1Context (string connectionString) : base(connectionString)
{
}
public DbSet<Table1> Table1s { get; set; }
public DbSet<Table2> Table2s { get; set; }
}
How would I define a class to be inherited where I can define a new connection string, and what would the new Db1-Db4 contexts look like as they inherit?

How to allow soft-deleted email to be reused again with ASP.NET UserIdentity

I have an ASP.NET application where users are authenticated using the UserIdentity class. Recently, I have just implemented a soft-delete feature by adding 'ActiveStatus' to the ApplicationUser class.
The issue arises where the user cannot re-register with the soft-deleted email address as a new account. Can someone help me with this?
I've just managed to achieve this in my MVC application using the instructions and sample code from https://www.codeguru.com/csharp/csharp/soft-deleting-entities-cleanly-using-entity-framework-6-interceptors.html posted by Rakesh Babu Paruchuri on August 28th, 2015
The sample code link from that blog entry is https://github.com/rakeshbabuparuchuri/EFExpensionPoints
In case those links become unavailable here are the key points:
It uses a custom attribute "SoftDeleteAttribute" with an Entity Framework Interceptor.
The key elements that I included in my own project were:
a class for the SoftDeleteAttribute inherited from System.Attribute
a SoftDeleteQueryVisitor class that inherits from System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder.DefaultExpressionVisitor
a SoftDeleteInterceptor class that inherits from System.Data.Entity.Infrastructure.Interception.IDbCommandTreeInterceptor
Then you register the interceptor - in my case I put the following code in the same file as my ApplicationDbContext (inherited from IdentityDbContext):
public class ApplicationDbConfiguration : DbConfiguration
{
public ApplicationDbConfiguration()
{
AddInterceptor(new Helpers.SoftDeleteInterceptor());
}
}
And override OnModelCreating to add a convention for dealing with the SoftDeleteAttribute:
var conv = new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
"SoftDeleteColumnName",
(type, attributes) => attributes.Single().ColumnName);
modelBuilder.Conventions.Add(conv);
The final step was adding the SoftDeleteAttribute to my ApplicationUser class.
[SoftDelete("IsDeleted")]
public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int>
{
//some code removed to emphasise the important bit
[StringLength(150)]
public string Forenames { get; set; }
[StringLength(50)]
public string Surname { get; set; }
public bool IsDeleted { get; set; }
}
In addition to this I've also dropped and re-created the unique index on the Username column of my users table in the database so that it uses a condition so that I can re-use the usernames of deleted users (not recommended but I'm using an existing database):
CREATE UNIQUE NONCLUSTERED INDEX [UserNameIndex]
ON [dbo].[tbl_user] ([UserName] ASC)
WHERE ([IsDeleted]=(0))
I also ran some migrations - I'm not sure if that migrations step is important for getting it to work, I've literally only done this myself today so haven't had a chance to try it against a manually-created database.
With these changes I can soft-delete users and then create new users with the same username and/or email address
I also found a similar solution at http://marisks.net/2016/02/27/entity-framework-soft-delete-and-automatic-created-modified-dates/ which also uses command interceptors, but replaces the SoftDelete Attribute with a fixed column name and has the code arranged a little differently. He does also include updating Created and Modified columns as well as the soft-delete flag. That article references's Rakesh's article which helped me find it :)

Asp Identity Custom context

I am building a single page application, so I used the visual studio default template.
When It was on development I had 2 databases Entityframework.mdf and Identity.mdf, because thats what the default configuration does, but now I need relation ship with the users and I can't reach them easly because they are in another database.
in an MVC template you can easly do it like this:
public class ApplicationUser: IdentityUser
{
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<CustomTableItem> CustomTable{ get; set; }
//You can add more tables
}
when you use the single page application it configures the user management in a way I don't understand.
UserManagerFactory = () => new UserManager<IdentityUser>(new UserStore<IdentityUser>());
then from this article
This code uses the default constructor for the UserStore class, which will create a new instance of an IdentityDbContext object since an object isn’t supplied. If you want to use your own IdentityDbContext derived class, like the MVC 5 project does, you can modify the above initialization code and pass in your own context.
it says I can modify it but it does not show how :(, and I have tried but I can’t make it work. This is what I am trying to do
UserManagerFactory = () => new UserManager<ApplicationUser>(new UserStore<ApplicationUser>());
what am I missig?
If you use default constructor (with not parameters) for UserStore class, this happens:
public UserStore()
{
this..ctor((DbContext) new IdentityDbContext());
this.DisposeContext = true;
}
Identity framework creates it's own database context for you with default connection string and no relation to your own models or DbContext.
What Scott says in his article is that UserStore has a constructor defined like this:
public UserStore(DbContext context)
{
base..ctor(context);
}
In other words you can supply your DbContext as a parameter into the constructor of UserStore:
UserManagerFactory = () => new UserManager<ApplicationUser>(
new UserStore<ApplicationUser>(new ApplicationDbContext()))
Where ApplicationDbContext is defined as you describe in the question.
You'll need to create a migration on ApplicationDbContext that will create Identity tables in Entityframework.mdf. Then you'll have to move data from Identity.mdf into your main database. Connect to both datbases and run something like this:
insert into EntityFramework.dbo.IdenetityUsers
select * from Identity.dbo.IdentityUsers
However, I've only done data migration from one DB to another one within single SQL Server instance, not between LocalDbs (I presume you used these). So this method might not work and you'll have to export data from Identity.mdf into csv files and import them into EntityFramework.mdf

Accessing stored procedures on a code generated DbContext with Entity Framework 4.1 with DDD

I'm working on a large project using ASP.Net MVC 3, EF 4.1 and Ninject for Dependecy Injection. I've read through many of the existing questions here regarding DDD, EF and the Repository Pattern but I can't seem to find anyone incorporating stored procedures with these patterns.
I don't like the idea of implementing yet another repository pattern on top of what seems to already be a UnitOfWork/RepositoryPattern already defined with a DbContext. Also, I generally don't like the idea of creating Service and Repository classes for every type of entity in the system if possible.
The source of my problem stems from this common repository interface which everyone seems to use.
public interface IRepository<TEntity> where TEntity : class
{
TEntity Get(Expression<Func<TEntity, bool>> whereClause);
IEnumerable<TEntity> List();
IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> whereClause);
void Add(TEntity entity);
void Delete(TEntity entity);
// And so on...
}
That's great if all your queries can be in context of a single entity. Where this breaks for me is when I want to access a stored procedure. With EF 4.1 & Code Generatrion you can add stored procedures (e.g. SelectUser) and it will generate a context which looks something like this.
namespace MyCompany.Data.Database
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using MyCompany.Domain.Entities;
using MyCompany.Domain.Contracts;
public partial class MyCompanyEntities : DbContext
{
public MyCompanyEntities()
: base("name=MyCompanyEntities")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Order> Orders { get; set; }
public DbSet<User> Users { get; set; }
public virtual ObjectResult<User> SelectUser(Nullable<int> userId)
{
((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace.LoadFromAssembly(typeof(User).Assembly);
var userIdParameter = userId.HasValue ?
new ObjectParameter("UserId", userId) :
new ObjectParameter("UserId", typeof(int)); MyCompanyEntities x; x.
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<User>("SelectUser", userIdParameter);
}
public virtual ObjectResult<User> SelectUser(Nullable<int> userId, MergeOption mergeOption)
{
((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace.LoadFromAssembly(typeof(User).Assembly);
var userIdParameter = userId.HasValue ?
new ObjectParameter("UserId", userId) :
new ObjectParameter("UserId", typeof(int));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<User>("SelectUser", mergeOption, userIdParameter);
}
}
}
As part of my DDD setup I have a UserService class and I would like to 'inject' a repository to its constructor. Many examples suggest that the constructor should accept an (IRepository<User> userRepository). This doesn't work for me. Stored procedures are generated on the DbContext class as a method and I am unable to see it.
The only thing I can think of is to either create another interface with the stored procedure methods on it. I don't really want to add it to the generic IRepository because then when you have an instance of IRepository<Order> you'll still see SelectUser which seems a bit odd. Maybe it's not a big deal?
Perhaps I'm going about this the wrong way. Should I not be bothering with creating an interface on top of my DbContext if I'm not trying to create a whole new repository pattern? I was really creating it for the dependency injection. Would it be wrong if the UserService constructor took a MyCompanyEntities instance instead of an interface?
What you found is natural. The problem is that generic repository is insufficient for real scenarios. It is only good for "base" implementation. You need specific repository for User entity which will expose method wrapping call to context exposed stored procedure.

ASP.NET MVC UpdateModel - fields vs properties?

I refactored some common properties into a base class and immediately my model updates started failing. UpdateModel() and TryUpdateModel() did not seem to update inherited public properties.
I cannot find detailed info on MSDN nor Google as to the rules or semantics of these methods. The docs are terse (http://msdn.microsoft.com/en-us/library/dd470933.aspx), simply stating:
Updates the specified model instance using values from the controller's current value provider.
SOLVED: MVC.NET does indeed handle inherited properties just fine. This turned out to have nothing to do with inheritance. My base class was implemented with public fields, not properties. Switching them to formal properties (adding {get; set; }) was all I needed. This has bitten me before, I keep wanting to use simple, public fields. I would argue that fields and properties are syntactically identical, and could be argued to be semantically equivalent, for the user of the class.
MVC will bind to properties of the inherited class. The model binder calls something like typeof(yourtype).GetProperties() which returns all the inherited members just fine.
Just tested it out with:
public class PersonBase
{
public string Name { get; set; }
}
public class User : PersonBase
{
public string FavoriteFood { get; set; }
}
"My assumption is the methods are reflecting on the top class only,"
How would that work? The "top" class IS the base class too.
this one made me curious too.
i made a edit form for a class Manager who derives from a Person
(after all, managers are persons too :-))
then in this action method
public ActionResult Edit(Manager manager )
{
return View(manager);
}
which wass called from a view with the Manager (derived type) as strong typed Model variable, when hovering the manager variable, it shows me the base class (it actually said: base: Person ) AND the one extra property for the manager
tried the formcollection too, and that also works:
public ActionResult Edit(FormCollection formCollection )
{
Manager manager = new Manager();
UpdateModel(manager );
return View(manager);
}

Resources