Почему пустует DI контейнер при корректном добавлении сервисов?
Проект на ASP .Net Core MVC. База данных MS SQL Server. Взаимодействие с бд, с помощью EF Core. Написал класс для инициализации созданных в нем списков данными из базы. Класс написан по шаблону "Singlton" , так как необходим один экземпляр этого класса.
Код класса инициализатора:
Код класса инициализатора
|
1 |
using VartanMVCv2.Domain.Repositories.Abstract; using VartanMVCv2.Domain.Entities; using Microsoft.EntityFrameworkCore; using System.Diagnostics; namespace VartanMVCv2.Domain { public class Modelinitializer : IDisposable { private static readonly Lazy<Modelinitializer> instanceLazy = new Lazy<Modelinitializer>(()=>new Modelinitializer()); private bool _disposed = false; private readonly IEntityRepository<WorkServices> _workServicesRepository; private readonly IEntityRepository<WorksList> _worksListRepository; private readonly IEntityRepository<WorksName> _workNameRepository; private readonly IEntityRepository<CompletedProject> _completedProjectRepository; private readonly IEntityRepository<CompletedProjectPhoto> _completedProjectPhotoRepository; private readonly IEntityRepository<Feedback> _feedbackRepository; private readonly ILogger<Modelinitializer> _logger; private readonly DbContext _dbContext; public List<WorkServices> workServicesList { get; set; } = new List<WorkServices>(); public List<WorksList> worksList { get; set; } = new List<WorksList>(); public List<WorksName> worksNameList { get; set; } = new List<WorksName>(); public List<CompletedProject> completedProjectsList { get; set; } = new List<CompletedProject>(); public List<CompletedProjectPhoto> completedProjectPhotosList { get; set; } = new List<CompletedProjectPhoto>(); public List<Feedback> feedbackList { get; set; } = new List<Feedback>(); public bool InitialFlag { get; protected set; } = false; private Modelinitializer() { } public Modelinitializer(IEntityRepository<WorkServices> workServicesRepository, IEntityRepository<WorksList> worksListRepository, IEntityRepository<WorksName> workNameRepository, IEntityRepository<CompletedProject> completedProject, IEntityRepository<CompletedProjectPhoto> completedProjectPhoto, IEntityRepository<Feedback> feedback, AplicationDBContext appDBContext, ILogger<Modelinitializer> logger) { _workServicesRepository = workServicesRepository; _worksListRepository = worksListRepository; _workNameRepository = workNameRepository; _completedProjectRepository = completedProject; _completedProjectPhotoRepository = completedProjectPhoto; _feedbackRepository = feedback; _dbContext = appDBContext; _logger = logger; } public static Modelinitializer CreateInstance () { return instanceLazy.Value; } public async Task ModelInitialAsync() { if (_workServicesRepository == null) { Debug.WriteLine("DI conteiner is empty"); } workServicesList = await _workServicesRepository.GetAllAsync(); worksList = await _worksListRepository.GetAllAsync(); worksNameList = await _workNameRepository.GetAllAsync(); completedProjectsList = await _completedProjectRepository.GetAllAsync(); completedProjectPhotosList = await _completedProjectPhotoRepository.GetAllAsync(); feedbackList = await _feedbackRepository.GetAllAsync(); _logger.LogInformation($"Инициализация списков, в рамках вызова метода ModelInitialAsync () завершена. Колличество элементов WorkServices: {workServicesList.Count} n" + $"WorksList: {worksList.Count} n" + $"WorksName: {worksNameList.Count} n" + $"CompletedProjectList: {completedProjectsList.Count} n" + $"CompletedProjectPhoto: {completedProjectPhotosList.Count} n" + $"Feedback: {feedbackList.Count}"); InitialFlag = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { // позже нужно реализовать удаление управляемых ресурсов } // тут очистка неуправляемых ресурсов _disposed = true; } ~Modelinitializer() { Dispose(false); } } } |
Репозиторий с CRUD методами подключил как сервис в DI контейнере. Вроде все везде корректно. Но при запуске приложения, вылетает System.NullReferenceException: "Object reference not set to an instance of an object." В Чем может быть дело? Почему экземпляры репозитория а вместе с ним и логгера не регестрируются в контейнере?
Класс Program(не копировал маршруты)
|
1 |
using VartanMVCv2.Domain.Entities; namespace VartanMVCv2 { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // add services builder.Services.AddControllersWithViews().AddSessionStateTempDataProvider(); //сопостовляем конфигурационный json с классом builder.Configuration.AddJsonFile("appsettings.json"); Config config = new Config(); builder.Configuration.Bind("Project", config); //подключаем класс контекста базы данных builder.Services.AddDbContext<AplicationDBContext>(x => x.UseSqlServer(Config.ConnectionString)); //подключаем нужный функционал в качестве сервисов builder.Services.AddMemoryCache(); builder.Services.AddTransient<Modelinitializer>(); builder.Services.AddTransient<IEntityRepository<WorkServices>, EFEntitiesRepository<WorkServices>>(); builder.Services.AddTransient<IEntityRepository<WorksList>, EFEntitiesRepository<WorksList>>(); builder.Services.AddTransient<IEntityRepository<WorksName>, EFEntitiesRepository<WorksName>>(); builder.Services.AddTransient<IEntityRepository<CompletedProject>, EFEntitiesRepository<CompletedProject>>(); builder.Services.AddTransient<IEntityRepository<CompletedProjectPhoto>, EFEntitiesRepository<CompletedProjectPhoto>>(); builder.Services.AddTransient<IEntityRepository<Feedback>, EFEntitiesRepository<Feedback>>(); builder.Services.AddTransient<DataManager>(); builder.Services.AddTransient<IndexViewModel>(); //настраиваем Identity builder.Services.AddIdentity<IdentityUser, IdentityRole>(opts => { opts.User.RequireUniqueEmail = false; opts.Password.RequiredLength = 6; opts.Password.RequireNonAlphanumeric = false; opts.Password.RequireLowercase = false; opts.Password.RequireUppercase = false; opts.Password.RequireDigit = false; }).AddEntityFrameworkStores<AplicationDBContext>().AddDefaultTokenProviders(); //autentificatio cookie builder.Services.ConfigureApplicationCookie(options => { options.Cookie.Name = "MyCompanyAuth"; options.Cookie.HttpOnly = true; options.LoginPath = "/account/login"; options.AccessDeniedPath = "/account/accesdenied"; options.SlidingExpiration = true; }); var app = builder.Build(); |
Исключение:
spoiler
System.NullReferenceException
HResult=0x80004003
Сообщение = Object reference not set to an instance of an object.
Источник = VartanMVCv2
Трассировка стека:
в VartanMVCv2.Domain.Modelinitializer.d__41.MoveNext() в C:UsersДмирийsourcereposAcceptme3VartanMVCv2DomainModelinitializer.cs:строка 64
Вот это вот все сервисы репозитория
|
1 |
builder.Services.AddTransient<IEntityRepository<WorkServices>, EFEntitiesRepository<WorkServices>>(); builder.Services.AddTransient<IEntityRepository<WorksList>, EFEntitiesRepository<WorksList>>(); builder.Services.AddTransient<IEntityRepository<WorksName>, EFEntitiesRepository<WorksName>>(); builder.Services.AddTransient<IEntityRepository<CompletedProject>, EFEntitiesRepository<CompletedProject>>(); builder.Services.AddTransient<IEntityRepository<CompletedProjectPhoto>, EFEntitiesRepository<CompletedProjectPhoto>>(); builder.Services.AddTransient<IEntityRepository<Feedback>, EFEntitiesRepository<Feedback>>(); |
Дополнительно:
Содержание
Нельзя idisposable экземпляр делать одиночкой. Вас не смущают настойчивые предупреждения компилятора о наличии непроинициализированных полей предназначенных только для чтения в классе?
насколько я понимаю, проблема в следующем. В классе инициализатора два конструктора: конструктор по умолчанию, приватный, инициализирует объект в который не попадают сервисы из DI контейнера т.к для этого определяется пользовательский конструктор с параметрами. Получается в итоге создается больше одного объекта инициализатора . Как это обойти? знаю что ответ простой но уже не одупляю.
UPD. Решил проблему выносом списков с данными в класс и его уже сделал одиночкой.
Ответы:
Ошибка говорит о том, что ошибка не в регистрации сервисов, а внутри GetAllAsync при foreach или материализации запроса.
|
1 |
workServicesList = await _workServicesRepository.GetAllAsync(); |
- не должно там быть ошибки. Эта часть кода работала исправно при другой реализации получения данных из бд. Я просто по сути попытался вынести листы в отдельный класс.
на всякий случай прилагаю репозиторий для сущьностей в бд.
spoilerPHP1using Microsoft.EntityFrameworkCore; using VartanMVCv2.Domain.Entities; using VartanMVCv2.Domain.Repositories.Abstract; namespace VartanMVCv2.Domain.Repositories.EntityFramework { public class EFEntitiesRepository <T> : IEntityRepository<T> where T :EntitiesBase { private readonly AplicationDBContext _dbContext; public EFEntitiesRepository(AplicationDBContext dBContext) { _dbContext = dBContext; } public void DeleteEntity(int id) { var entity = GetById(id); _dbContext.Set<T>().Remove(entity); _dbContext.SaveChanges(); } public IQueryable<T> GetAll() { return _dbContext.Set<T>(); } public async Task<List<T>> GetAllAsync() { IQueryable<T> entities = GetAll(); List<T> entitiesList = await entities.ToListAsync(); return entitiesList; } public T GetById(int id) { return _dbContext.Set<T>().FirstOrDefault(x => x.ID == id)!; } public T GetByTitle(string title) { return _dbContext.Set<T>().FirstOrDefault(x => x.Title == title)!; } public void SaveEntities(T entity) { _dbContext.Entry(entity).State = EntityState.Modified; _dbContext.SaveChanges(); } public void Added(T entity) { _dbContext.Set<T>().Add(entity); _dbContext.SaveChanges(); } } }
Попробуйте убрать конструктор без параметров в Modelinitializer.
- Убрать конструктор не получится потому что мне нужно создать экземпляр этого класса. Разве что переписать класс инициализатора как сервис но тогда мне придется и контекст базы данных делать а это уже геморрой. Почему провайдер сервисов не использует отведенный ему конструктор с параметрами?
- Попытался убрать конструктор по умолчанию. Вместо него создал и сделал приватным другой конструктор с одним параметром . ошибка та же, ничего не меняется.
- Дмитрий, попробуйте пометить конструктор атрибутом [ActivatorUtilitiesConstructor]
Для решения данной проблемы вы можете воспользоваться услугами фрилансеров. Мы выполним необходимую работу быстро и качественно.
Оставить комментарий Отменить
Ответы
- Есть ответ! к записи Как уменьшить масштаб меньше 100% в Windows 10 (22H2)
- Есть ответ! к записи Аналоги CloudFlare в России?
- Есть ответ! к записи Аналоги CloudFlare в России?
- Есть ответ! к записи Как называется человек, который дизайн придумает для сайта и сверстает его?
- Есть ответ! к записи Можно ли установить Яндекс.Диск на АльтЛинукс?
- Есть ответ! к записи Картинки мутные только на сафари, есть выход?
- Есть ответ! к записи Keenetic. Как настроить SSTP клиент с сертификатом?
- Есть ответ! к записи Чем заменить executor в aiogram 3?
Пустой DI контейнер может возникнуть по нескольким причинам, давайте рассмотрим их и возможные способы решения:
1. Неправильное добавление сервисов: убедитесь, что вы правильно добавляете сервисы в DI контейнер. Каждый сервис должен быть добавлен с уникальным идентификатором, чтобы DI контейнер мог правильно его идентифицировать. Также убедитесь, что вы не добавляете один и тот же сервис несколько раз.
2. Отсутствие зависимостей: если в ваших сервисах есть зависимости от других сервисов, убедитесь, что эти зависимости также добавлены в DI контейнер. В противном случае DI контейнер не сможет создать экземпляр сервиса из-за отсутствия необходимых зависимостей.
3. Не правильная конфигурация DI контейнера: убедитесь, что вы правильно настраиваете DI контейнер и используете правильные методы для добавления и получения сервисов. Например, вы можете использовать методы add() и get() для добавления и получения сервисов соответственно.
Если после выполнения вышеперечисленных шагов DI контейнер все еще остается пустым, возможно проблема в другом месте вашего приложения. Проверьте логи ошибок и убедитесь, что все зависимости и конфигурации загружаются правильно. Если проблема продолжает оставаться, попробуйте использовать отладчик для более детального анализа процесса создания DI контейнера.