2

I'm trying to use ninject with asp.net identity and currently I was doing the following for the bindings:

kernel.Bind(typeof(IUserStore<>)).To(typeof(UserStore<>));

Here you have the classes definitions:

public interface IUser : IUser<string>

public interface IUserStore<TUser> : IUserStore<TUser, string>, IDisposable where TUser : class, IUser<string>

public class IdentityUser : IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>, IGenerateKeys

public class UserStore<TUser> : UserStore<TUser, IdentityRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUserStore<TUser>, IUserStore<TUser, string> where TUser : IdentityUser, new()

public class Context {
    public Context(ILogger Logger, Dictionary<string, string> LocalConfig, IUserStore<IUser> UserManager
         ){...}
}

When I try to do kernel.Get<Context>() I get the error about not being able to cast IUserStore to UserStore.

Unable to cast object of type 'UserStore`1[IdentityUser]' to type 'Microsoft.AspNet.Identity.IUserStore`1[Microsoft.AspNet.Identity.IUser]'.

I don't really understand why this is not working but in fact trying the following IUserStore<IdentityUser> dummy = new Store<IdentityUser>() gives no compilation error, but this IUserStore<IUser> dummy = new Store<IdentityUser>() does, but i can't understande why since IdentityUser implements IUser.

Anyone had any similar problem?

FEST
  • 813
  • 2
  • 14
  • 37
  • 1
    You are confusing the generic parameter with the type itself. When you change the type parameter of a generic object, you change it's actual type. So an `IUserStore` is not the same thing as an `IUserStore`, and you cannot assign one to the other. Imagine trying to assign a `List` to a `List`. it doesn't matter if the generic types are implementations of each other. Now, you CAN add an IdentityUser object to a IUserStore object, but that's not the same thing as trying to assign the actual UserStore of another type. – Erik Funkenbusch Apr 06 '17 at 17:27
  • 1
    I should clarify a bit more. While what I said above is true, there ARE ways in .NET 4 based languages (C# and VB) to do this, but it requires that the interfaces be specified to do it. This is called Covariance (or Contravariance for the opposite way of doing it). The IUser and IUserStore interfaces do not implement this, so the point still stands. You can read up more on variance here: https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx – Erik Funkenbusch Apr 06 '17 at 18:05

1 Answers1

1

If you look at Microsoft.AspNet.Identity.EntityFramework you can see TUser in UserStore must be type of IdentityUser and not IUser, that's why you got compilation error.

public namespace Microsoft.AspNet.Identity.EntityFramework
{
//
// Summary:
//     EntityFramework based user store implementation that supports IUserStore, IUserLoginStore,
//     IUserClaimStore and IUserRoleStore
//
// Type parameters:
//   TUser:
public class UserStore<TUser> : UserStore<TUser, IdentityRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>, IUserStore<TUser>, IUserStore<TUser, string>, IDisposable where TUser : IdentityUser
{
    //
    // Summary:
    //     Default constuctor which uses a new instance of a default EntityyDbContext
    public UserStore();
    //
    // Summary:
    //     Constructor
    //
    // Parameters:
    //   context:
    public UserStore(DbContext context);
   }
}

You should always use IdentityUser, since IUser is just a minimal interface for IdentityUser.

If you want to use Ninject with Identity, it would be a lite bit tricky, you can find the step by step solution here : How to inject User Manager to Account Controller with default Identity Model in Identity 2 using Ninject

Community
  • 1
  • 1
Mona Moravej
  • 141
  • 7