我希望我的ApplicationContext构造函数将UserManager作为参数,但是依赖注入有问题.
码:
public class ApplicationContext : IdentityDbContext<ApplicationUser> { private IHttpContextAccessor _contextAccessor { get; set; } public ApplicationUser ApplicationUser { get; set; } private UserManager<ApplicationUser> _userManager; public ApplicationContext(DbContextOptions<ApplicationContext> options,IHttpContextAccessor contextAccessor,UserManager<ApplicationUser> userManager) : base(options) { _contextAccessor = contextAccessor; var user = _contextAccessor.HttpContext.User; _userManager = userManager; ApplicationUser = _userManager.Users.FirstOrDefault(u => u.Id == _userManager.GetUserId(user)); } }
在startup.cs中
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddDbContext<ApplicationContext>(options => options.UsesqlServer(Configuration.GetConnectionString("DefaultConnection"),b => b.MigrationsAssembly("RCI.App"))); services.AddIdentity<ApplicationUser,IdentityRole>() .AddEntityFrameworkStores<ApplicationContext>() .AddDefaultTokenProviders(); services.AddAuthentication(); services.AddMvc(); // Add application services. services.AddTransient<IEmailSender,AuthMessageSender>(); services.AddTransient<ISmsSender,AuthMessageSender>(); services.AddTransient<IHttpContextAccessor,HttpContextAccessor>(); services.AddOptions(); }
A circular dependency was detected for the service of type
‘Microsoft.AspNetCore.Identity.UserManager`1[RCI.App.Models.ApplicationUser]’.
谁能指出我做错了什么?
解决方法
循环依赖通常是应用程序设计不当的标志,应该进行修改.正如我在评论中已经提到的,拥有依赖于用户管理器的数据库上下文似乎不是一个好主意.这使我假设您的数据库上下文做得太多,可能违反了
single-responsibility principle.
只是查看数据库上下文的依赖关系,您已经在其中添加了太多特定于应用程序的状态:您不仅依赖于用户管理器,还依赖于HTTP上下文访问器;并且您也在构造函数中立即解析HTTP上下文(这通常不是最好的主意).
从您的代码摘录中,您似乎想要检索当前用户以供以后使用.如果您想使用它来过滤用户的查询,那么您应该考虑将其静态烘焙到数据库上下文实例中是否真的是个好主意.考虑在方法中接受ApplicationUser.这样,您可以摆脱所有这些依赖关系,使您的数据库上下文更易于测试(因为用户不再是上下文的状态),并且您还可以使上下文的单一责任更加清晰:
public IList<Thing> GetThings (ApplicationUser user) { // just an example… return Things.Where(t => t.UserId == user.Id).ToList(); }
请注意,这也是inversion of control.而不是让数据库上下文主动检索它应该查询的用户(这将增加另一个责任,违反SRP),它希望传递应该查询的用户,将控件移动到调用代码.
现在,如果您经常查询当前用户的内容,解析控制器中的当前用户然后将其传递给数据库上下文可能会有些烦人.在这种情况下,创建一个服务no longer repeat yourself.该服务可以依赖于数据库上下文和其他东西来找出当前用户.