| File: RoleStoreBase.cs | Web Access |
| Project: src\aspnetcore\src\Identity\Extensions.Stores\src\Microsoft.Extensions.Identity.Stores.csproj (Microsoft.Extensions.Identity.Stores) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Shared; namespace Microsoft.AspNetCore.Identity; /// <summary> /// Creates a new instance of a persistence store for roles. /// </summary> /// <typeparam name="TRole">The type of the class representing a role.</typeparam> /// <typeparam name="TKey">The type of the primary key for a role.</typeparam> /// <typeparam name="TUserRole">The type of the class representing a user role.</typeparam> /// <typeparam name="TRoleClaim">The type of the class representing a role claim.</typeparam> public abstract class RoleStoreBase<TRole, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TKey, TUserRole, TRoleClaim> : IQueryableRoleStore<TRole>, IRoleClaimStore<TRole> where TRole : IdentityRole<TKey> where TKey : IEquatable<TKey> where TUserRole : IdentityUserRole<TKey>, new() where TRoleClaim : IdentityRoleClaim<TKey>, new() { /// <summary> /// Constructs a new instance of <see cref="RoleStoreBase{TRole, TKey, TUserRole, TRoleClaim}"/>. /// </summary> /// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param> public RoleStoreBase(IdentityErrorDescriber describer) { ArgumentNullThrowHelper.ThrowIfNull(describer); ErrorDescriber = describer; } private bool _disposed; /// <summary> /// Gets or sets the <see cref="IdentityErrorDescriber"/> for any error that occurred with the current operation. /// </summary> public IdentityErrorDescriber ErrorDescriber { get; set; } /// <summary> /// Creates a new role in a store as an asynchronous operation. /// </summary> /// <param name="role">The role to create in the store.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>A <see cref="Task{TResult}"/> that represents the <see cref="IdentityResult"/> of the asynchronous query.</returns> public abstract Task<IdentityResult> CreateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> /// Updates a role in a store as an asynchronous operation. /// </summary> /// <param name="role">The role to update in the store.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>A <see cref="Task{TResult}"/> that represents the <see cref="IdentityResult"/> of the asynchronous query.</returns> public abstract Task<IdentityResult> UpdateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> /// Deletes a role from the store as an asynchronous operation. /// </summary> /// <param name="role">The role to delete from the store.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>A <see cref="Task{TResult}"/> that represents the <see cref="IdentityResult"/> of the asynchronous query.</returns> public abstract Task<IdentityResult> DeleteAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> /// Gets the ID for a role from the store as an asynchronous operation. /// </summary> /// <param name="role">The role whose ID should be returned.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>A <see cref="Task{TResult}"/> that contains the ID of the role.</returns> public virtual Task<string> GetRoleIdAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); ArgumentNullThrowHelper.ThrowIfNull(role); return Task.FromResult(ConvertIdToString(role.Id)!); } /// <summary> /// Gets the name of a role from the store as an asynchronous operation. /// </summary> /// <param name="role">The role whose name should be returned.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>A <see cref="Task{TResult}"/> that contains the name of the role.</returns> public virtual Task<string?> GetRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); ArgumentNullThrowHelper.ThrowIfNull(role); return Task.FromResult(role.Name); } /// <summary> /// Sets the name of a role in the store as an asynchronous operation. /// </summary> /// <param name="role">The role whose name should be set.</param> /// <param name="roleName">The name of the role.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns> public virtual Task SetRoleNameAsync(TRole role, string? roleName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); ArgumentNullThrowHelper.ThrowIfNull(role); role.Name = roleName; return Task.CompletedTask; } /// <summary> /// Converts the provided <paramref name="id"/> to a strongly typed key object. /// </summary> /// <param name="id">The id to convert.</param> /// <returns>An instance of <typeparamref name="TKey"/> representing the provided <paramref name="id"/>.</returns> [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "TKey is annotated with RequiresUnreferencedCodeAttribute.All.")] public virtual TKey? ConvertIdFromString(string? id) { if (id == null) { return default(TKey); } return (TKey?)TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(id); } /// <summary> /// Converts the provided <paramref name="id"/> to its string representation. /// </summary> /// <param name="id">The id to convert.</param> /// <returns>An <see cref="string"/> representation of the provided <paramref name="id"/>.</returns> public virtual string? ConvertIdToString(TKey id) { if (id.Equals(default(TKey))) { return null; } return id.ToString(); } /// <summary> /// Finds the role who has the specified ID as an asynchronous operation. /// </summary> /// <param name="id">The role ID to look for.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>A <see cref="Task{TResult}"/> that result of the look up.</returns> public abstract Task<TRole?> FindByIdAsync(string id, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> /// Finds the role who has the specified normalized name as an asynchronous operation. /// </summary> /// <param name="normalizedName">The normalized role name to look for.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>A <see cref="Task{TResult}"/> that result of the look up.</returns> public abstract Task<TRole?> FindByNameAsync(string normalizedName, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> /// Get a role's normalized name as an asynchronous operation. /// </summary> /// <param name="role">The role whose normalized name should be retrieved.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>A <see cref="Task{TResult}"/> that contains the name of the role.</returns> public virtual Task<string?> GetNormalizedRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); ArgumentNullThrowHelper.ThrowIfNull(role); return Task.FromResult(role.NormalizedName); } /// <summary> /// Set a role's normalized name as an asynchronous operation. /// </summary> /// <param name="role">The role whose normalized name should be set.</param> /// <param name="normalizedName">The normalized name to set</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns> public virtual Task SetNormalizedRoleNameAsync(TRole role, string? normalizedName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); ArgumentNullThrowHelper.ThrowIfNull(role); role.NormalizedName = normalizedName; return Task.CompletedTask; } /// <summary> /// Throws if this class has been disposed. /// </summary> protected void ThrowIfDisposed() { ObjectDisposedThrowHelper.ThrowIf(_disposed, this); } /// <summary> /// Dispose the stores /// </summary> public void Dispose() => _disposed = true; /// <summary> /// Get the claims associated with the specified <paramref name="role"/> as an asynchronous operation. /// </summary> /// <param name="role">The role whose claims should be retrieved.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>A <see cref="Task{TResult}"/> that contains the claims granted to a role.</returns> public abstract Task<IList<Claim>> GetClaimsAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> /// Adds the <paramref name="claim"/> given to the specified <paramref name="role"/>. /// </summary> /// <param name="role">The role to add the claim to.</param> /// <param name="claim">The claim to add to the role.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns> public abstract Task AddClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> /// Removes the <paramref name="claim"/> given from the specified <paramref name="role"/>. /// </summary> /// <param name="role">The role to remove the claim from.</param> /// <param name="claim">The claim to remove from the role.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns> public abstract Task RemoveClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> /// A navigation property for the roles the store contains. /// </summary> public abstract IQueryable<TRole> Roles { get; } /// <summary> /// Creates a entity representing a role claim. /// </summary> /// <param name="role">The associated role.</param> /// <param name="claim">The associated claim.</param> /// <returns>The role claim entity.</returns> protected virtual TRoleClaim CreateRoleClaim(TRole role, Claim claim) => new TRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value }; }