Исключение поставщика услуг при регистрации диспетчера пользователей для пользователя шаблона - PullRequest
0 голосов
/ 18 апреля 2019

Я изучаю 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. Я не понимаю, почему это происходит с тех пор Я четко сказал where TEntity : User.

Спасибо! Постскриптум Я удалил некоторый код и некоторые emthods, чтобы сделать этот пост более читабельным. P.S.S: Класс MedicRepository расширяет UserRepository и вызывает base и пока не содержит ничего другого. UnitOfWork содержит все репозитории приложений и вызывает new для каждого из них внутри своего конструктора. P.S.S.S. Я хотел использовать шаблоны для этого хранилища, чтобы избежать приведения внутри контроллеров. Используется для возврата данных, связанных с пользователем.

1 Ответ

1 голос
/ 19 апреля 2019

Я понял это. Было недостаточно зарегистрировать сервис для 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

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...