Search code examples
c#asp.netasp.net-mvcvalidationasp.net-identity-3

ASP.NET Identity - Custom role validation not being called


I am trying to the create a custom RoleValidator object to validate my custom IdentityRole. I have created an ApplicaitonRoleValidator class that inherits from RoleValidator and set this as the RoleValidator in my ApplicationRoleManager class. But when I create new role the validation function ValidateAsync is never called.

I have tried looking at similar questions implementing UserValidator like How can customize Asp.net Identity 2 username already taken validation message? and this one ASP.NET Identity - setting UserValidator does nothing but cannot get it to work.

/// <summary>
/// Custom role validator, used to validate new instances of ApplicationRole that are added to the system.
/// </summary>
/// <typeparam name="TRole">The type of the role.</typeparam>
public class ApplicationRoleValidator<TRole> : RoleValidator<TRole> where TRole : ApplicationRole
{
    private RoleManager<TRole, string> Manager { get; set; }

    /// <summary>
    /// Initializes a new instance of the <see cref="ApplicationRoleValidator" /> class.
    /// </summary>
    /// <param name="manager">The manager.</param>
    public ApplicationRoleValidator(RoleManager<TRole, string> manager) : base(manager)
    {
        Manager = manager;
    }

    /// <summary>
    /// Validates a role before saving.
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    /// <exception cref="System.ArgumentNullException">item</exception>
    public override async Task<IdentityResult> ValidateAsync(TRole item)
    {
        if (item == null)//<= break point here never reached.
        {
            throw new ArgumentNullException(nameof(item));
        }

        var rslt = base.ValidateAsync(item);
        if (rslt.Result.Errors.Any())
        {//return error if found
            return IdentityResult.Failed(rslt.Result.Errors.ToArray());
        }

        var errors = new List<string>();
        //validate the min num of members
        if (role.MinimumNumberOfMembers < 0)
        {
            errors.Add(string.Format(CultureInfo.CurrentCulture, "最小数は0以上でなければなりません。"));
        }

        return errors.Count > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success;
    }
}

ApplicationRoleManager where the custom RoleValidator is set during create. I can break on that line so I know it is being called.

public class ApplicationRoleManager : RoleManager<ApplicationRole, string>
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ApplicationRoleManager"/> class.
    /// </summary>
    /// <param name="store"></param>
    public ApplicationRoleManager(IRoleStore<ApplicationRole, string> store)
        : base(store)
    {
    }
    /// <summary>
    /// Creates the specified options.
    /// </summary>
    /// <param name="options">The options.</param>
    /// <param name="context">The context.</param>
    /// <returns></returns>
    public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
    {
        var manager = new ApplicationRoleManager(new ApplicationRoleStore(context.Get<MyContext>()));
        manager.RoleValidator = new ApplicationRoleValidator<ApplicationRole>(manager);
        return manager;
    }
}
public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
    public bool IsSystemGroup { get; set; }
    public string Description { get; set; } = "";
    public int MinimumNumberOfMembers { get; set; }
}

public class ApplicationRoleStore : RoleStore<ApplicationRole, string, ApplicationUserRole>
{
    public ApplicationRoleStore(MyContext context)
        : base(context)
    {
    }
}

The role is being created by call to Create on the ApplicationRoleManager

var store = new ApplicationRoleStore(new MyContext());
var manager = new ApplicationRoleManager(store);
manager.Create(group);

Solution

  • You are setting the ApplicationRoleValidator as RoleValidator of ApplicationRoleManager in Create method of ApplicationRoleManager. In the 3 last lines of code you posted, you are newing an instance of ApplicationRoleManager. This instance of ApplicationRoleManager gets the default RoleValidator.

    If you want to new an instance of ApplicationRoleManager you have to put that logic inside constructor

    public ApplicationRoleManager(IRoleStore<ApplicationRole, string> store) : base(store)
    {
         RoleValidator = new ApplicationRoleValidator<ApplicationRole>(this);
    }