我尝试从我的控制器中注入ASP.NET身份的ApplicationUserManager。 这是我尝试注入的类:
public class ApplicationUserManager : UserManager<ApplicationUser>, IApplicationUserManager
{ ... }
这是我尝试注入我的控制器的方式:
private readonly IApplicationUserManager _userManager;
public MyController(IApplicationUserManager userManager)
{
_userManager = userManager;
}
问题是当我尝试从_userManager获取方法时,当我写_userManager.
时,intellisense只给出了Async方法。例如_userManager.RemoveFromRoleAsync()
而不是_userManager.RemoveFromRole()
。
发生这种情况是因为我的界面只有异步方法。但同步方法(非异步)是UserManager的扩展方法。
public static class UserManagerExtensions
{ ...
public static IdentityResult RemoveFromRole<TUser, TKey>(this UserManager<TUser, TKey> manager, TKey userId,
string role)
where TKey : IEquatable<TKey>
where TUser : class, IUser<TKey>
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
return AsyncHelper.RunSync(() => manager.RemoveFromRoleAsync(userId, role));
}
...}
UserManager也派生自另一个类:
public class UserManager<TUser> : UserManager<TUser, string> where TUser : class, IUser<string>
{
...
}
问题是:我如何设法在我的控制器中获取同步方法???
答案 0 :(得分:0)
由于扩展方法适用于类定义而不是接口,因此您还需要先将from和IApplicationUserManager转换为UserManager。不幸的是,从DI和嘲弄的角度来看,这不是很好的做法。 为了说明这一点,这应该有用......
if (IApplicationUserManager is UserManager)
{
UserManager userManager = (UserManager)IApplicationUserManager ;
userManager.RemoveFromRole(...)
}
但我不建议这样做,因为控制器不应该知道实现,这就是你的问题所在。事实上,扩展方法本质上只是在类实现上定义,接口不了解它。
因此,将扩展方法功能放在接口上声明的方法中实际上可能更好。
答案 1 :(得分:0)
DI不需要接口,它需要抽象。由于您的实现是子类,因此您的抽象是UserManager<ApplicationUser>
是有效的。这也意味着UserManager<ApplicationUser>
的另一个实现是有效的。
public class ApplicationUserManager : UserManager<ApplicationUser>
{ ... }
private readonly UserManager<ApplicationUser> _userManager;
public MyController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
现在,如果你的控制器依赖于当前IApplicationUserManager
的其他成员(我希望如此),你需要将这些成员变成一个抽象基类,以便它可以注入你的控制器,所以它也可以继承UserManager<ApplicationUser>
。
public class ApplicationUserManager : ApplicationUserManagerBase
{ ... }
public abstract class ApplicationUserManagerBase : UserManager<ApplicationUser>
{ ... }
private readonly ApplicationUserManagerBase _userManager;
public MyController(ApplicationUserManagerBase userManager)
{
_userManager = userManager;
}
要进行实施或模拟,您只需要继承ApplicationUserManagerBase
。这比cast更好,因为实现与抽象松散耦合。
哦,回到原来的问题 - 如果你采用这种方法,UserManager<TUser, TKey>
的所有扩展方法都可以在ApplicationUserManager
上使用。扩展方法定义中的重要线索是:this UserManager<TUser, TKey> manager
- 您必须定义一个包含此抽象的抽象,以使其工作。