如何使用扩展方法注入类? ASP.NET身份

时间:2014-11-06 08:58:17

标签: c# asp.net-mvc inversion-of-control extension-methods asp.net-identity

我尝试从我的控制器中注入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>
    {
     ...
     }

问题是:我如何设法在我的控制器中获取同步方法???

2 个答案:

答案 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 - 您必须定义一个包含此抽象的抽象,以使其工作。