英文:
Why don't async methods in identity services in ASP.NET Core have a parameter for CancellationToken?
问题
为什么像Asp.Net Core中的身份验证服务中的async
方法(例如userManager.FindByNameAsync(username)
)没有CancellationToken
参数?
我知道它具有一个属性,其值为CancellationToken.None
,并将其传递给Entity Framework方法,但它从未设置过值,而且它是只读的,我无法为其设置值。
针对这个问题有哪些解决方案?
英文:
My question is why async
methods like userManager.FindByNameAsync(username)
in identity Services in Asp.Net Core do not have a parameter for CancellationToken
?
I know it has a property with CancellationToken.None
value and pass to Entityframework methods but it never sets a value and it`s read only and I cannot set a value for that
What are the solutions for this problem?
When I want to override CancellationToken
in My custom service which inherited from userManager
答案1
得分: 1
> 它从不设置一个值,而且它是只读的,我不能为它设置一个值。对于这个问题有什么解决办法。
检查这里的代码 1
public class AspNetUserManager<TUser> : UserManager<TUser>, IDisposable where TUser : class
{
private readonly CancellationToken _cancel;
/// <summary>
/// 构造 <see cref="AspNetUserManager{TUser}"/> 的新实例。
/// </summary>
/// <param name="store">管理器将操作的持久化存储。</param>
/// <param name="optionsAccessor">用于访问 <see cref="IdentityOptions"/> 的访问器。</param>
/// <param name="passwordHasher">保存密码时要使用的密码哈希实现。</param>
/// <param name="userValidators">要针对用户进行验证的 <see cref="IUserValidator{TUser}"/> 集合。</param>
/// <param name="passwordValidators">要针对密码进行验证的 <see cref="IPasswordValidator{TUser}"/> 集合。</param>
/// <param name="keyNormalizer">生成用户索引键时要使用的 <see cref="ILookupNormalizer"/>。</param>
/// <param name="errors">用于提供错误消息的 <see cref="IdentityErrorDescriber"/>。</param>
/// <param name="services">用于解析服务的 <see cref="IServiceProvider"/>。</param>
/// <param name="logger">用于记录消息、警告和错误的日志记录器。</param>
public AspNetUserManager(IUserStore<TUser> store,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TUser> passwordHasher,
IEnumerable<IUserValidator<TUser>> userValidators,
IEnumerable<IPasswordValidator<TUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<UserManager<TUser>> logger)
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
_cancel = services?.GetService<IHttpContextAccessor>()?.HttpContext?.RequestAborted ?? CancellationToken.None;
}
/// <summary>
/// 与当前 HttpContext.RequestAborted 关联的取消令牌,如果不可用则为 CancellationToken.None。
/// </summary>
protected override CancellationToken CancellationToken => _cancel;
}
你可以尝试
protected override CancellationToken CancellationToken => _cancel;
private CancellationToken _cancel { get; set; }
在你的目标方法中:
public async Task<IdentityResult> AsyncMethod(IdentityUser user,CancellationToken token)
{
_cancel = token;
....;
}
英文:
> it never sets a value and it`s read only and I cannot set a value for
> that What are the solutions for this problem
Check the codes here
public class AspNetUserManager<TUser> : UserManager<TUser>, IDisposable where TUser : class
{
private readonly CancellationToken _cancel;
/// <summary>
/// Constructs a new instance of <see cref="AspNetUserManager{TUser}"/>.
/// </summary>
/// <param name="store">The persistence store the manager will operate over.</param>
/// <param name="optionsAccessor">The accessor used to access the <see cref="IdentityOptions"/>.</param>
/// <param name="passwordHasher">The password hashing implementation to use when saving passwords.</param>
/// <param name="userValidators">A collection of <see cref="IUserValidator{TUser}"/> to validate users against.</param>
/// <param name="passwordValidators">A collection of <see cref="IPasswordValidator{TUser}"/> to validate passwords against.</param>
/// <param name="keyNormalizer">The <see cref="ILookupNormalizer"/> to use when generating index keys for users.</param>
/// <param name="errors">The <see cref="IdentityErrorDescriber"/> used to provider error messages.</param>
/// <param name="services">The <see cref="IServiceProvider"/> used to resolve services.</param>
/// <param name="logger">The logger used to log messages, warnings and errors.</param>
public AspNetUserManager(IUserStore<TUser> store,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TUser> passwordHasher,
IEnumerable<IUserValidator<TUser>> userValidators,
IEnumerable<IPasswordValidator<TUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<UserManager<TUser>> logger)
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
_cancel = services?.GetService<IHttpContextAccessor>()?.HttpContext?.RequestAborted ?? CancellationToken.None;
}
/// <summary>
/// The cancellation token associated with the current HttpContext.RequestAborted or CancellationToken.None if unavailable.
/// </summary>
protected override CancellationToken CancellationToken => _cancel;
}
You could try
protected override CancellationToken CancellationToken => _cancel;
private CancellationToken _cancel { get; set; }
in your target method:
public async Task<IdentityResult> AsyncMethod(IdentityUser user,CancellationToken token)
{
_cancel = token;
....;
}
答案2
得分: 1
短答案是出于设计考虑,因为值无法更改。
与需求相关,UserManager.cs的自定义实现或至少需要的特定方法可能是一个解决方案,如果没有HttpContext.RequestAborted
是唯一阻止UserManager异步调用的取消令牌。
长答案,不可变属性的值不会更改,它的值唯一更改的方式是在基类/抽象类的构造函数中。覆盖虚属性的值在派生类中同样适用,意味着一直有两个值,一个在基类中,一个在派生类中。即使属性是可变的,从派生类引用base.whatever时,当明确分配了某些内容时,会更改基类的值。
示例:
using Xunit;
namespace Tests
{
public class MyBase
{
public MyBase()
{
}
public MyBase(int immutableInt)
{
ImmutableInt = immutableInt;
}
protected virtual int ImmutableInt { get; } = -1;
protected virtual int MutableInt { get; set; } = -1;
}
public class MyDriven : MyBase
{
public MyDriven()
{
}
public MyDriven(int value)
{
ImmutableInt = value;
MutableInt = value;
}
public MyDriven(int immutableInt, int mutableInt1) : base(immutableInt)
{
ImmutableInt = immutableInt;
MutableInt = mutableInt1;
}
protected override int ImmutableInt { get; }
protected override int MutableInt => base.MutableInt;
public int ImmutableIntReadonly => ImmutableInt;
public int BaseImmutableIntReadonly => base.ImmutableInt;
public int MutableIntReadonly => MutableInt;
public int BaseMutableIntReadonly => base.MutableInt;
}
public class ImmutableTests
{
[Fact]
public void TestImutableOverride()
{
MyDriven imutable = new MyDriven(1);
Assert.Equal(1, imutable.ImmutableIntReadonly);
Assert.Equal(-1, imutable.BaseImmutableIntReadonly);
Assert.Equal(1, imutable.MutableIntReadonly);
Assert.Equal(1, imutable.BaseMutableIntReadonly);
MyDriven imutableCtor = new MyDriven(1, 1);
Assert.Equal(1, imutableCtor.ImmutableIntReadonly);
Assert.Equal(1, imutableCtor.BaseImmutableIntReadonly);
Assert.Equal(1, imutableCtor.MutableIntReadonly);
Assert.Equal(1, imutableCtor.BaseMutableIntReadonly);
}
}
}
英文:
Short answer is by design because value cannot change.
Related to the needs, custom implementation of UserManager.cs or at least specific methods needed may be a solution, if not HttpContext.RequestAborted
is the only cancellation token stopping UserManager async invocations.
Long answer, value of an immutable property won't change, the only way in can change the value is in the constructor of base/abstract class.
Overwritten value of a virtual property is in the driven class same rule apply, meaning all the time there are two values, one in base one in driven. Even if property is mutable, referring from driven at base.whatever when explicitly assigned something will change base value.
Example:
using Xunit;
namespace Tests
{
public class MyBase
{
public MyBase()
{
}
public MyBase(int immutableInt)
{
ImmutableInt = immutableInt;
}
protected virtual int ImmutableInt { get; } = -1;
protected virtual int MutableInt { get; set; } = -1;
}
public class MyDriven : MyBase
{
public MyDriven()
{
}
public MyDriven(int value)
{
ImmutableInt = value;
MutableInt = value;
}
public MyDriven(int immutableInt, int mutableInt1): base(immutableInt)
{
ImmutableInt = immutableInt;
MutableInt = mutableInt1;
}
protected override int ImmutableInt { get; }
protected override int MutableInt => base.MutableInt;
public int ImmutableIntReadonly => ImmutableInt;
public int BaseImmutableIntReadonly => base.ImmutableInt;
public int MutableIntReadonly => MutableInt;
public int BaseMutableIntReadonly => base.MutableInt;
}
public class ImmutableTests
{
[Fact]
public void TestImutableOverride()
{
MyDriven imutable = new MyDriven(1);
Assert.Equal(1, imutable.ImmutableIntReadonly);
Assert.Equal(-1, imutable.BaseImmutableIntReadonly);
Assert.Equal(1, imutable.MutableIntReadonly);
Assert.Equal(1, imutable.BaseMutableIntReadonly);
MyDriven imutableCtor = new MyDriven(1, 1);
Assert.Equal(1, imutableCtor.ImmutableIntReadonly);
Assert.Equal(1, imutableCtor.BaseImmutableIntReadonly);
Assert.Equal(1, imutableCtor.MutableIntReadonly);
Assert.Equal(1, imutableCtor.BaseMutableIntReadonly);
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论