none
Cambiar de cadena de conexión por inquilino - ASP.NET EFCore 3.1 RRS feed

  • Pregunta

  • Hola 

    Trabajo con ASP.NET EFCore 3.1, SQL Server 2019, Web API

    Necesito crear la cadena de conexión por inquilino, tengo la siguiente implementación

    Controller

    [Authorize]
        [Route("api/[controller]")]
        [ApiController]
        public class UsuarioController : ControllerBase
        {
            private readonly ISdUsuario _sdUsuario;
            private readonly IMapper _mapper;
            private readonly IHttpContextAccessor _httpContextAccessor;
            private readonly ITenantProvider _tenantProvider;
            public UsuarioController(ISdUsuario sdUsuario, IMapper mapper, IHttpContextAccessor httpContextAccessor,
                ITenantProvider tenantProvider)
            {
                _sdUsuario = sdUsuario;
                _mapper = mapper;
                _httpContextAccessor = httpContextAccessor;
                _tenantProvider = tenantProvider;
    
            }
    
            [HttpGet("[action]")]
            public async Task<bool> Autentificar([FromQuery] string user, [FromQuery] string password)
            {//UsuarioDto usuarioDto
                var usuarioDto = new UsuarioDto()
                {
                    User = user,
                    Password = password
                };
    
                var usuario = _mapper.Map<Usuario>(usuarioDto);
                var exist = await _sdUsuario.Autentificar(usuario);
                if (exist)
                    return exist;
                return exist;
            }
        }

    En la capa acceso a datos tengo la siguiente clase, la idea es obtener los reclamos por medio de IHttpContextAccessor, luego teniendo el inquilino obtenr la cadena de conexión e ir agregando la cadena de conexión en una lista, para después desde el context poder obtenerla por medio del inquilino haciendo una búsqueda en la lista.

    public class WebTenantProvider : ITenantProvider
        {
            private readonly InquilinoRepository _inquilinoRepository = new InquilinoRepository();
            private readonly List<Conexion> _conexionItem = new List<Conexion>();
            private List<Conexion> DetalleItemTemp => _conexionItem.ToList();
            private string _nameTenant = string.Empty;
    
    
            public WebTenantProvider(IHttpContextAccessor accessor)
            {
                _nameTenant = accessor.HttpContext.User.Claims
                    .Where(c => c.Type == ClaimsIdentity.DefaultNameClaimType).FirstOrDefault().Value;
            }
    
            private async Task GetConexions()
            {
                var entity = await _inquilinoRepository.Single(x => x.Nombre == _nameTenant,
                    new List<Expression<Func<Inquilino, object>>>() { x => x.BaseDato });
    
                var conexion = new Conexion()
                {
                    Tenant = entity.Nombre,
                    DatabaseConnectionString = entity.BaseDato.DatabaseConnectionString
                };
    
                AgregarConexion(conexion);
            }
    
            public async Task<string> GetName()
            {
                return await Task.Run(() => _nameTenant);
            }
    
            private void AgregarConexion(Conexion conexion)
            {
    
                foreach (var tenant in DetalleItemTemp)
                {
                    //Si el tenant ya existe en la lista ya no lo agrego, solo establesco nombre de tenant
                    if (tenant.Tenant == conexion.Tenant)
                    {
                        _nameTenant = conexion.Tenant;
                    }
                    else
                    {
                        //Si el tenant no existe lo agrego a la lista y establesco nombre de tenant
                        _conexionItem.Add(conexion);
                        _nameTenant = conexion.Tenant;
                    }
                }
    
                if (DetalleItemTemp.Count == 0)
                {
                    _conexionItem.Add(conexion);
                    _nameTenant = conexion.Tenant;
                }
            }
    
            public async Task<IEnumerable<Conexion>> MostrarConexiones()
            {
                var exist = DetalleItemTemp.Any(x => x.Tenant == _nameTenant);
                if (!exist)
                    await GetConexions();
                return await Task.Run(() => DetalleItemTemp.ToList());
            }
        }

    Context

    public class BusinessContext : DbContext
        {
            private List<Conexion> _detalleItemTemp;
            private string _nameTenan = string.Empty;
            private ITenantProvider _tenantProvider;
    
            public BusinessContext()
            {
    
            }
    
            public BusinessContext(DbContextOptions<BusinessContext> options, ITenantProvider tenantProvider)
                : base(options)
            {
                _tenantProvider = tenantProvider;
                _nameTenan = _tenantProvider.GetName().Result;
                _detalleItemTemp = _tenantProvider.MostrarConexiones().Result.ToList();
            }
    
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                //optionsBuilder.UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Business;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False");
                
    
                var ConnectionString = _detalleItemTemp.Where(x => x.Tenant == _nameTenan)
                        .FirstOrDefault().DatabaseConnectionString;
                optionsBuilder.UseSqlServer(ConnectionString);
            }

    El problema es que cuando persisto no entra en el constructor sobrecarcado

    public BusinessContext(DbContextOptions<BusinessContext> options, ITenantProvider tenantProvider)

    Esta entrando por public BusinessContext()

    Es por eso que no puedo llamar a los métodos implementados en WebTenantProvider, ¿como lo puedo solucionar?, ¿Que estoy haciendo mal?

    Startup

    public void ConfigureServices(IServiceCollection services)
            {
    
                services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
                services.AddControllers().AddNewtonsoftJson(options =>
                {
                    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                });
    
    
    
                var connectionString = Configuration.GetConnectionString("CatalogoInquilino");
                services.AddDbContext<CatalogoContext>(options =>
                {
                    options.UseSqlServer(connectionString);
                });
    
                services.AddDbContext<BusinessContext>(options => options.UseSqlServer(connectionString));
                services.AddScoped<ITenantProvider, WebTenantProvider>();
                services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    
                services.AddTransient<ISdServidor, SdServidor>();
                services.AddTransient<ISdBaseDato, SdBaseDato>();
                services.AddTransient<ISdInquilino, SdInquilino>();
                services.AddTransient<ISdUsuario, SdUsuario>();
    
                services.AddScoped(typeof(IInquilinoRepository<>), typeof(BaseInquilinoRepository<>));
    
    
    
                services.AddHttpContextAccessor();
                services.AddSingleton(new Startup(Configuration));
    
                services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                }).AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = Configuration["Authentication:Issuer"],
                        ValidAudience = Configuration["Authentication:Audience"],
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Authentication:SecretKey"]))
                    };
                });
            }
    

    Saludos!


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    miércoles, 5 de agosto de 2020 18:15

Todas las respuestas

  • Hola Pedro Ávila, 

      

    Gracias por levantar tu consulta en los foros de MSDN. Entendimos su pregunta y vamos a darle seguimiento para buscar la mejor repuesta pertinente al caso.  

    Cualquier duda referente a productos Microsoft, puedes consultarnos. Es un gusto informarte. 

    Gracias por usar los foros de MSDN.   

    Eric Ruiz

     ____________________________ 

      

    Por favor recuerde "Marcar como respuesta" las respuestas que hayan resuelto su problema, es una forma común de reconocer a aquellos que han ayudado, y hace que sea más fácil para los otros visitantes encontrar la solución más tarde.  

    Microsoft ofrece este servicio de forma gratuita, con la finalidad de ayudar a los usuarios y la ampliación de la base de datos de conocimientos relacionados con los productos y tecnologías de Microsoft.   

    Este contenido es proporcionado "tal cual" y no implica ninguna responsabilidad de parte de Microsoft. 

     

    miércoles, 5 de agosto de 2020 22:35
    Moderador