es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Usando una fábrica de contexto de base de datos en Blazor server.

Estoy teniendo algunos problemas para configurar la conexión de base datos EF para mi aplicación Blazor del lado del servidor. Funcionaba con la configuración estándar DbContext hasta que noté que había problemas con la conexión que no se cerraba correctamente debido a que Blazor usaba el mismo contexto en todo momento. Mi investigación me llevó a ver DbContextFactory, pero la interfaz IDbContextFactory está obsoleta y se prefiere IDesignTimeDbContextFactory.

He configurado una clase para implementar la interfaz:

public class FIS2ContextFactory : IDesignTimeDbContextFactory<FIS2_DbContext>
{
    private readonly DbContextOptions<FIS2_FranklinContext_AutoGenerated> options;

    public FIS2ContextFactory(DbContextOptions<FIS2_FranklinContext_AutoGenerated> contextOptions)
    {
        options = contextOptions;
    }

    public FIS2_DbContext CreateDbContext(string[] args)
    {
        return new FIS2_DbContext(options);
    }
}

El DbContext que quiero utilizar es el siguiente, que hereda y amplía el DbContext generado por EF Power Tools:

public partial class FIS2_DbContext : FIS2_FranklinContext_AutoGenerated
{
    public FIS2_DbContext()
    {
    }

    public FIS2_DbContext(DbContextOptions<FIS2_FranklinContext_AutoGenerated> options) : base(options)

    {
    }

    public virtual DbSet<StudentBasicDetailsWithCurrentTg> StudentBasicDetailsWithCurrentTgs { get; set; }
    public virtual DbSet<CurriculumSearchBasicDetails> CurriculumSearchBasicDetails { get; set; }
    public virtual DbSet<StudentAllEnrolments> StudentAllEnrolments { get; set; }
}

En mi startup.cs lo tengo configurado así en el método ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContextFactory<FIS2_DbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("FIS2")));

        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddScoped<IFileService, FileService>();
        services.AddScoped<IEmailService, EmailService>();
        services.AddScoped<ITimetableService, TimetableService>();
        services.AddScoped<ICurriculumService, CurriculumServiceEf>();
        services.AddScoped<IStudentService, StudentServiceEf>();
        services.AddScoped<ICollectionService, CollectionsServiceEf>();
        services.AddHttpContextAccessor();
        services.AddHttpClient();
        services.AddAuthenticationCore();
        services.AddAuthentication(IISDefaults.AuthenticationScheme);
        services.AddAuthorization();
        services.AddSyncfusionBlazor();
        services.AddScoped<SessionState>();
    }

Mi problema es que cuando se trata de configurar los servicios que utilizan esta conexión de base de datos, me encuentro con este mensaje de error en el program.cs:

Algunos servicios no pueden construirse (Error al validar el descriptor de servicio ‘ServiceType: DataLibrary.Data.Interfaces.ITimetableService Lifetime: Scoped ImplementationType: DataLibrary.Data.BusinessLayer.TimetableService’: No se puede resolver el servicio para el tipo ‘DataLibrary.Models.FIS2ContextFactory’ mientras se intenta activar ‘DataLibrary.Data.BusinessLayer.TimetableService’. ) (Error al validar el descriptor de servicio ‘ServiceType: DataLibrary.Data.Interfaces.ICurriculumService Lifetime: Scoped ImplementationType: DataLibrary.Data.BusinessLayer.CurriculumServiceEf’: No se puede resolver el servicio para el tipo ‘DataLibrary.Models.FIS2ContextFactory’ mientras se intenta activar ‘DataLibrary.Data.BusinessLayer.CurriculumServiceEf’.) (Error al validar el descriptor de servicio ‘ServiceType: DataLibrary.Data.Interfaces.IStudentService Lifetime: Scoped ImplementationType: DataLibrary.Data.BusinessLayer.StudentServiceEf’: No se puede resolver el servicio para el tipo ‘DataLibrary.Models.FIS2ContextFactory’ mientras se intenta activar ‘DataLibrary.Data.BusinessLayer.StudentServiceEf’.) (Error al validar el descriptor de servicio ‘ServiceType: DataLibrary.Data.Interfaces.ICollectionService Lifetime: Scoped ImplementationType: DataLibrary.Data.BusinessLayer.CollectionsServiceEf’: No se puede resolver el servicio para el tipo ‘DataLibrary.Models.FIS2ContextFactory’ mientras se intenta activar ‘DataLibrary.Data.BusinessLayer.CollectionsServiceEf’.)

Para referencia, aquí está un ejemplo de cómo se configura TimetableService (los otros se instancian de la misma manera):

using DataLibrary.Data.Interfaces;
using DataLibrary.Models;
using DataLibrary.Models.timetable;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace DataLibrary.Data.BusinessLayer
{
    public class TimetableService : ITimetableService
    {
        private FIS2ContextFactory _contextFactory;

        public TimetableService(FIS2ContextFactory db)
        {
            _contextFactory = db;
        }

        public async Task<List<spGetHolidaysBetweenDatesResult>> GetHolidaysBetweenDatesAsync(DateTime startDate, DateTime endDate)
        {
            string[] args = { "" };
            var _db = _contextFactory.CreateDbContext(args);
            var procedures = _db.Procedures;

            return await procedures.spGetHolidaysBetweenDatesAsync(startDate, endDate);
        }

        public async Task<List<PeriodsBetweenDates>> GetPeriodsBetweenDatesAsync(DateTime startDate, DateTime endDate)
        {
            string[] args = { "" };
            var _db = _contextFactory.CreateDbContext(args);
            var procedures = _db.Procedures;
            var toReturn = new List<PeriodsBetweenDates>();
            var results = await procedures.spGetPeriodsBetweenDatesAsync(startDate, endDate);
            foreach (var item in results)
            {
                toReturn.Add(new PeriodsBetweenDates(item.Date, item.Timetable, item.BlockCode, item.StartTime, item.EndTime));
            }
            return toReturn;
        }

        public async Task<List<StudentTimetable>> GetStudentTimetableAsync(DateTime startDate, DateTime endDate, string studentID)
        {
            string[] args = { "" };
            var _db = _contextFactory.CreateDbContext(args);
            var procedures = _db.Procedures;
            var results = await procedures.spGetStudentTimetableAsync(startDate, endDate, studentID);

            List<StudentTimetable> studentTimetables = new List<StudentTimetable>();
            foreach (var item in results)
            {
                studentTimetables.Add(JsonConvert.DeserializeObject<StudentTimetable>(item.timetable));
            }
            return studentTimetables;
        }
    }
}

¿Es debido a que estoy usando el método incorrecto para crear la fábrica de contexto en la puesta en marcha, o es algo más adelante que tengo mal?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El mensaje de error sugiere que DataLibrary.Models.FIS2ContextFactory no se puede resolver cuando se están construyendo los servicios que lo utilizan. Esto podría ser porque no está registrado en el contenedor de inyección de dependencias o porque está registrado incorrectamente.

    En el método ConfigureServices del archivo startup.cs, se utiliza el método AddDbContextFactory para registrar FIS2_DbContext en el contenedor de inyección de dependencias. Este método toma una función de fábrica que crea instancias de DbContext cuando se necesitan. Sin embargo, cuando se están construyendo los servicios, las clases TimetableService, CurriculumServiceEf, StudentServiceEf y CollectionsServiceEf buscan una instancia de FIS2ContextFactory en sí y no el DbContext que crea.

    Para solucionar este problema, FIS2ContextFactory en sí necesita ser registrado en el contenedor de inyección de dependencias. Esto se puede hacer agregándolo al método ConfigureServices:

    services.AddSingleton<FIS2ContextFactory>();
    

    Esto registra una instancia singleton de FIS2ContextFactory en el contenedor de inyección de dependencias. Una vez hecho esto, los otros servicios que lo utilizan pueden ser actualizados para aceptar una instancia de FIS2ContextFactory directamente:

    public class TimetableService: ITimetableService
    {
        private FIS2ContextFactory _contextFactory;
    
        public TimetableService(FIS2ContextFactory contextFactory)
        {
            _contextFactory = contextFactory;
        }
    
        // ...
    }
    

    Al cambiar el constructor de cada servicio para aceptar una instancia de FIS2ContextFactory directamente, los servicios pueden ser construidos correctamente por el contenedor de inyección de dependencias con la instancia correcta de FIS2_DbContext.

Comments are closed.