我正在学习ASP .NET Core,今天我偶然发现了一些东西。我有User
类继承IdentityUser
并添加一些自定义字段,如名字,姓氏等...
User
类进一步扩展到其他类型的用户,最多只添加一个或两个额外的字段。我决定采用这条路线,因为没有必要在4个地方重复相同的代码。
我已经定义了一个UserRepository
,它实现了一个接口IUserRepository<TEntity> where TEntity : User
。每当我尝试访问Index
时,我都会遇到如下异常:
InvalidOperationException: No service for type 'Microsoft.AspNetCore.Identity.UserManager`1[HM.models.users.Medic]' has been registered.
Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<T>(IServiceProvider provider)
HM.repositories.UserRepository<TEntity>..ctor(ApplicationDbContext context, IServiceProvider serviceProvider, string role) in UserRepository.cs
+
_userManager = serviceProvider.GetRequiredService<UserManager<TEntity>>();
HM.repositories.MedicRepository..ctor(ApplicationDbContext context, IServiceProvider serviceProvider) in MedicRepository.cs
+
public MedicRepository(ApplicationDbContext context, IServiceProvider serviceProvider) : base(context, serviceProvider, _role) { }
HM.persistence.UnitOfWork..ctor(ApplicationDbContext context, IServiceProvider _serviceProvider) in UnitOfWork.cs
+
Medics = new MedicRepository(_context, _serviceProvider);
app.Controllers.MedicController.Index() in MedicController.cs
+
using (var unitOfWork = new UnitOfWork(_context, _serviceProvider))
Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor+TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
这些是一些代码片段:
MedicController
:
// GET: Medic
public async Task<IActionResult> Index()
{
using (var unitOfWork = new UnitOfWork(_context,_serviceProvider))
{
return View(await unitOfWork.Medics.GetAll());
}
}
UserRepository
和IUserRepository
:
public interface IUserRepository<TEntity> where TEntity : User
{
Task Add(TEntity user, string password);
Task Remove(TEntity user);
Task Update(TEntity user);
Task<IEnumerable<TEntity>> GetAll();
Task<TEntity> GetById(string id);
Task<bool> Any(Func<TEntity, bool> predicate);
}
public class UserRepository<TEntity> : IUserRepository<TEntity> where TEntity : User
{
private readonly string _role;
private readonly UserManager<TEntity> _userManager;
public UserRepository(ApplicationDbContext context, IServiceProvider serviceProvider, string role)
{
_role = role;
_userManager = serviceProvider.GetRequiredService<UserManager<TEntity>>();
}
public async Task<IEnumerable<TEntity>> GetAll()
{
return await _userManager.GetUsersInRoleAsync(_role);
}
}
最后,医生:
[Table("Medic")]
public class Medic : User
{
[DisplayName("Departments")]
public ICollection<MedicDepartment> departments { get; set; }
[DisplayName("Diagnostics")]
public ICollection<MedicDiagnostic> diagnostics { get; set; }
[PersonalData]
[DisplayName("Rank")]
[StringLength(30, MinimumLength = 3, ErrorMessage = "The rank name must be between 3 and 30 characters long!")]
public string rank { get; set; }
}
我调试了应用程序:它将在_userManager = serviceProvider.GetRequiredService<UserManager<TEntity>>();
中的UserRepository
抛出此异常。我不明白为什么这个hapens,因为我已经明确说明where TEntity : User
。
谢谢!附:我删除了一些代码和一些方法,使这篇文章更加可更新。 P.S.S:MedicRepository
类扩展UserRepository
并调用base
并且暂时包含其他内容。 UnitOfWork
包含所有应用程序存储库,并在其构造函数中的每一个上调用new
。 P.S.S.S.我想为此存储库使用模板,以避免在控制器内部进行转换。它曾用于返回“用户”相关数据。
我想到了。仅为UserManager<User>
注册服务是不够的,但我还必须为继承UserManager
的每种类型的用户注册User
。
首先,我将这些线添加到Startup.cs
内的ConfigureServices
。这使用IdentityCore
而不是Identity
。
services.AddIdentityCore<Medic>() //add the derived user type from custom user
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<Medic, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
其次,不要忘记添加经理。与以前相同,在同一文件和方法中,添加:
services.AddScoped<UserManager<User>, UserManager<User>>(); //the user manager for the base type of User
services.AddScoped<UserManager<Medic>, UserManager<Medic>>(); //the user manager for Medics
希望能帮助到你!