Asp.net core Connection string dinamica

di il
18 risposte

Asp.net core Connection string dinamica

Salve a tutti, questa è la prima volta che scrivo nel forum relativo ad asp.net, in quanto è da pochissimo che mi cimento con asp.net core e C#.
sto creando una app che prende i dati da diversi database identici per tipi di tabelle ma diversi per dati quindi ho creato il dbcontetx che vorrei fare agganciare al database in base alla scelta del cliente ed ho abbozzato questo codice:
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using paghe.Models;
using paghe.ViewModels;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Http;

namespace paghe.data
{
    public class PagheContext : DbContext
    {
        public PagheContext()
        {
        }

        public string Conn { get; set; }
        
        private readonly IHttpContextAccessor _HttpContextAccessor;
        public PagheContext(DbContextOptions<PagheContext> options, IHttpContextAccessor HttpContextAccessor)
        : base(options)
        {
            _HttpContextAccessor = HttpContextAccessor;
            Conn = "Paghe" + _HttpContextAccessor.HttpContext.Session.GetString("ConCliente");
            System.Diagnostics.Debug.WriteLine("Test" + Conn);
        }
        
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            IConfigurationRoot configuration = new ConfigurationBuilder()
                .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                .AddJsonFile("appsettings.json")
                .Build();
            
            System.Diagnostics.Debug.WriteLine("Test2" + Conn);
            optionsBuilder.UseSqlServer(configuration.GetConnectionString(Conn"));
        }

        public DbSet<User> Users { get; set; }
in pratica al momento di scegliere il cliente creo un HttpContext con il numero del cliente
il problema sta nel fatto che, sicuramente perchè ancora non ho padronanza di C#, è che non riesco e portare la stringa Conn in OnConfiguring
tanè che come si vede dal debug che ho fatto il primo test mi da la variabile Conn come mi serve ma nel secondo test non legge niente:
dbcontext.JPG
dbcontext.JPG

Qualcuno saprebbe indirizzarmi sulla strada giusta?

18 Risposte

  • Re: Asp.net core Connection string dinamica

    Ciao

    Non mi è chiara una cosa. Parli di agganciare il database in base alla scelta del cliente...
    Cosa intendi esattamente?
  • Re: Asp.net core Connection string dinamica

    Ciao Pigi,
    Come da premessa questa App mi serve appunto per studiare, e secondo me il modo migliore per imparare è fare prove su problemi reali in modo da sbattere il muso nella pratica.
    Ringraziandoti anticipatamente per tutto l aiuto che mi riuscirai a dare ti spiego meglio come ho pensato di far funzionare il programma
    nella pagine generale c'è l elenco dei Clienti e gli utenti dei singoli clienti selezionano il loro, e si apre la pagina del login

    su appsettings.json ci sono N connessioni quanti sono i clienti es:
    "Paghe51": "Server= NNWHSTSQL01\\WHSTSQL01;DataBase=Cliente1; User ID=****; Password=****;",
    "Paghe52": "Server= NNWHSTSQL01\\WHSTSQL01;DataBase= Cliente2; User ID= **** ; Password=**** ;"
    etc etc

    quando Seleziono il cliente creo un httpcontex di questo tipo:
    HttpContext.Session.SetString("ConCliente", "51")
    HttpContext.Session.SetString("ConCliente", "52")

    Nel metodo OnConfiguring
    
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                IConfigurationRoot configuration = new ConfigurationBuilder()
                    .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                    .AddJsonFile("appsettings.json")
                    .Build();
                
                optionsBuilder.UseSqlServer(configuration.GetConnectionString("Paghe51"));
            }
     
    se cambio manualmente GetConnectionString da "Paghe51" a "Paghe52" aggancia perfettamente il database quindi vorrei inserire dinamicamente il valore della GetConnectionString e creare qualcosa del genere:
    
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                IConfigurationRoot configuration = new ConfigurationBuilder()
                    .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                    .AddJsonFile("appsettings.json")
                    .Build();
                
                Conn = "Paghe" + _HttpContextAccessor.HttpContext.Session.GetString("ConCliente");
                optionsBuilder.UseSqlServer(configuration.GetConnectionString(Conn));
            }
    

    ma così non funziona non mi legge HttpContext. Altresì ho visto che inserendola qui
    
           public PagheContext(DbContextOptions<PagheContext> options, IHttpContextAccessor HttpContextAccessor)
            : base(options)
            {
                _HttpContextAccessor = HttpContextAccessor;
                Conn = "Paghe" + _HttpContextAccessor.HttpContext.Session.GetString("ConCliente");
                System.Diagnostics.Debug.WriteLine("Test" + Conn);
            }
            
    e facendo il debug la variabile Conn viene letta perfettamente.

    In giro ho trovato un codice molto simile
     
        private IConfigurationRoot _config;
        private HttpContext _httpContext;
    
        public MyDbContext(DbContextOptions options, IConfigurationRoot config, IHttpContextAccessor httpContextAccessor) 
              : base(options)
        {
            _config = config;
            _httpContext = httpContextAccessor.HttpContext;
        }
        
         protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var connString = BuildConnectionString(); // Your connection string logic here
    
            optionsBuilder.UseSqlServer(connString);
        }
        
    ma essendo ancora alle primissime armi con aspt net core e C#
    non ho capito come popolare la connString
    Vorrei se è possibile un consiglio per capire come fare.
    Grazie
  • Re: Asp.net core Connection string dinamica

    Ciao

    Grazie per la spiegazione, adesso il problema è molto più chiaro:
  • Re: Asp.net core Connection string dinamica

    Pigi, grazie mille a livello teorico credo di aver capito... ovviamente devo svilupparlo, inoltre mi dai dato dei consigli anche per un altra cosa che volevo provare a fare, cioè collegare l app sia ai databese dell Hosting che al database presente nel server in ufficio per fare delle sincronizzazioni ora inizio a fare delle prove spero di non avere più bisogno dei tuoi consigli.
    Grazie ancora ti faccio sapere
  • Re: Asp.net core Connection string dinamica

    Buongiorno Pigi, scusa il disturbo ho abbozzato il codice ma mi da un errore : CS1503 Argomento 2: non è possibile convertire da 'gruppo di metodi' a 'Type' su services.AddScoped(DatabaseFactory.GetDbContextBase);
    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using paghe.Models;
    using paghe.ViewModels;
    using Microsoft.Extensions.Options;
    using Microsoft.Extensions.Configuration;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.DependencyInjection;
    
    namespace paghe.data
    {
        public class PagheContext : DbContext
        {
            public PagheContext(object conn)
            {
            }
            public static class DatabaseFactory
            {
                private static readonly IHttpContextAccessor _HttpContextAccessor;
    
                public static PagheContext GetDbContextBase(IServiceProvider serviceProvider, IHttpContextAccessor HttpContextAccessor)
                {
                var CodiceCliente = "Paghe" + _HttpContextAccessor.HttpContext.Session.GetString("ConCliente");// recuperi l'ID dall'HttpContext o da dove lo hai salvato
                var dbGenerale = serviceProvider.GetService<PagheSVRContext>();
                
                var conn = dbGenerale.Connessione.Where(x => x.CodiceCliente == CodiceCliente).Select(x => x.ConnectionString).SingleOrDefault(); // recuperi la connection string
                return new PagheContext(conn); // Ritorni il DbContext istanziato
                }
            }
    
            // Configurazione del motore DI in Startup.cs
            public void ConfigureServices(IServiceCollection services)
            {
            services.AddScoped(DatabaseFactory.GetDbContextBase);
            }
    
    vorrei capire se sono nella strada giusta.
    Grazie
    Allegati:
    23890_1abb7aa3b86bbf0bbffb01ce8de1ccf2.jpg
    23890_1abb7aa3b86bbf0bbffb01ce8de1ccf2.jpg
  • Re: Asp.net core Connection string dinamica

    Ciao

    Non avevo esplicitato tutto e qualcosa era sbagliato (ho scritto tutto a mano).
    Ho fatto un test veloce (niente DbContext ma classe generica), provo a girarti i passaggi e il codice.

    Innanzi tutto crei una normale applicazione MVC (dotnet new mcv --nohttps -n TestConfig).
    A questo punto, nella cartella di root (TestConfig) crei queste classi:

    - Database: nel tuo caso reale è il DbContext specifico. Nel mio esempio è una classe stupida che ha una stringa di connessione che poi visualizza tramite apposita proprietà
    - DatabaseFactory: è la factory che istanzia il database in base al contesto. In questo esempio prendiamo i valori dalla query string, nel tuo caso prendilo da dove vuoi

    Quindi, nella cartella Controllers, crei la classe DatabaseController (è quello che poi chiameremo dal browser).

    Questo è il codice delle tre classi (ricordati di metterle nei percorsi giusti):
    
    ----------------------------------------------------------
    DATABASE
    ----------------------------------------------------------
    
    namespace TestConfig
    {
    
        /// <summary>
        /// Uso una classe di passaggio per semplicità,
        /// nel tuo caso è il DbContext che ti interessa
        /// </summary>
        public class MyDatabase 
        {
    
            public MyDatabase(string connectionString)
            {
                ConnectionString = connectionString;
            }
    
    
            /// <summary>
            /// Torno la connection string giusto per verificare che
            /// sia diversa a seconda della chiamata
            /// </summary>
            public string ConnectionString { get; private set; }
        }
    
    
    
    }
    
    ----------------------------------------------------------
    FACTORY
    ----------------------------------------------------------
    
    using System;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Primitives;
    
    namespace TestConfig
    {
    
        /// <summary>
        /// Factory per la creazione del Database
        /// </summary>
        public class DatabaseFactory
        {
    
            public DatabaseFactory(IServiceProvider provider, IHttpContextAccessor httpContextAccessor = null)
            {
                ServiceProvider = provider;
                HttpContextAccessor = httpContextAccessor;  
            }
    
    
            public IServiceProvider ServiceProvider { get; private set; }
    
            public IHttpContextAccessor HttpContextAccessor { get; private set;}
    
            /// <summary>
            /// Torniamo il MyDatabase richiesto
            /// </summary>
            public MyDatabase GetDatabase()
            {
                // Il provider non lo uso, a te serve per accedere al DB per recuperare la stringa di connessione.
                // Io controllo valore 1 o 2 giusto per non implementare tutto
                if (HttpContextAccessor == null) return new MyDatabase("Niente http context");
                
                HttpContextAccessor.HttpContext.Request.Query.TryGetValue("connectionId", out StringValues connId);
                switch (connId.ToString().ToUpper())
                {
                    case "PRIMA":
                        return new MyDatabase("Prima connessione");
                    case "SECONDA":
                        return new MyDatabase("Seconda connessione");
                    default:
                        return new MyDatabase("Impostare il valore connectionId nella query");
                }
            }
    
        }
    
    }
    
    
    
    ----------------------------------------------------
    CONTROLLER
    ----------------------------------------------------
    
    using Microsoft.AspNetCore.Mvc;
    
    namespace TestConfig.Controllers
    {
    
        /// <summary>
        /// Controller del database
        /// </summary>
        public class DatabaseController : Controller
        {
    
            public DatabaseController(MyDatabase database)
            {
                MyDatabase = database;
            }
    
    
            private MyDatabase MyDatabase { get; }
    
    
            /// <summary>
            /// Torniamo la stringa di connessione (per vedere se funziona)
            /// </summary>
            public IActionResult Index()
            {
                return Ok(MyDatabase.ConnectionString);
            }
        }
    }
    
    

    A questo punto, devi configurare il motore di DI nella classe Startup.cs, metodo ConfigureServices:
    
    
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllersWithViews();
                services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
                services.AddScoped<DatabaseFactory>();
                services.AddScoped<MyDatabase>(sp => {
                    var factory = sp.GetRequiredService<DatabaseFactory>();
                    return factory.GetDatabase();
                });
            }
    
    

    Tutto qui!

    Puoi fare la prova:
    localhost:5000/database -> Torna il database con scritto di impostare la variabile (nel tuo caso, non loggato)
    localhost:5000/database?connectionId=prima -> Torna "Prima Connessione" (nel tuo caso, il DbContext con una conn)
    localhost:5000/database?connectionId=seconda -> Torna "Seconda Connessione" (nel tuo caso, il DbContext con un'altra conn)
  • Re: Asp.net core Connection string dinamica

    Buongiorno e Buona Domenica!

    Sto Lavorando sul codice che mi hai consigliato ho fatto il TestConfig e tutto OK!!

    ora però credo di avere un problema sul DbContext:

    questo è il DbContext che ho fatto
     using Microsoft.EntityFrameworkCore;
    using paghe.Models;
    using paghe.ViewModels;
    using Microsoft.Extensions.Configuration;
    
    namespace paghe
    {
        public class PagheContext : DbContext
        {
            public PagheContext(string connectionString)
            {
                ConnectionString = connectionString;
            }
    
            public PagheContext()
            {
            }
    
            /// <summary>
            /// Torno la connection string giusto per verificare che
            /// sia diversa a seconda della chiamata
            /// </summary>
            public string ConnectionString { get; private set; }
    
            public PagheContext(DbContextOptions<PagheContext> options)
             : base(options)
            {
            }
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                 if (!optionsBuilder.IsConfigured)
                {
                    optionsBuilder.UseSqlServer(ConnectionString);
                }
            }
    
            public DbSet<User> Users { get; set; }
            public DbSet<Dipendenti> Dipendenti { get; set; }
        }
    }
    
    credo che l ' errore sia che non riesco a capire come collegare il DatabaseFactory al DbContext o meglio come popolare il valore di ConnectionString con quella di connId nel DatabaseFactory

    questo è il DatabaseFactory
    
    using System;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Primitives;
    
    namespace paghe
    {
        /// <summary>
        /// Factory per la creazione del Database
        /// </summary>
        public class DatabaseFactory
        {
            public DatabaseFactory(IServiceProvider provider, IHttpContextAccessor httpContextAccessor = null)
            {
                ServiceProvider = provider;
                HttpContextAccessor = httpContextAccessor;
            }
    
            public IServiceProvider ServiceProvider { get; private set; }
            public IHttpContextAccessor HttpContextAccessor { get; private set; }
    
            public PagheContext GetDatabase()
            {
                // Il provider non lo uso, a te serve per accedere al DB per recuperare la stringa di connessione.
                // Io controllo valore 1 o 2 giusto per non implementare tutto
                if (HttpContextAccessor == null) return new PagheContext("Niente http context");
                //HttpContextAccessor.HttpContext.Request.Query.TryGetValue("ConCliente", out StringValues connId);
                string connId = HttpContextAccessor.HttpContext.Session.GetString("ConCliente");
                switch (connId.ToString().ToUpper())
                {
                    case "51":
                        return new PagheContext("Server= 192.168.1.103\\SQLDACES,****; Database=*************db1;User ID=***; Password=*****;");
                    case "56":
                        return new PagheContext("Server= 192.168.1.103\\SQLDACES,****; Database=*************db2;User ID=***; Password=*****;");
                    default:
                        return new PagheContext("Server= 192.168.1.103\\SQLDACES,****; Database=*************db1;User ID=***; Password=*****;");
                }
            }
         }
    }
    
    Grazie per la pazienza
  • Re: Asp.net core Connection string dinamica

    Ho un altro Quesito... (scusa)
    io valorizzavo HttpContextAccessor con
    
    HttpContextAccessor.HttpContext.Session.SetString("ConCliente", "56");
    
    e lo recuperavo con
    
    string connId = HttpContextAccessor.HttpContext.Session.SetString("ConCliente", "56");
    
    che comunque funziona, meglio facendo il debug me lo valorizza.

    Ma per capire meglio
    perchè hai usato il Request e non la Session?
    HttpContextAccessor.HttpContext.Request.Query.TryGetValue("ConCliente", out StringValues connId);
    
    come si valorizza il Request?
  • Re: Asp.net core Connection string dinamica

    Ciao

    L'oggetto Request ci mette a disposizione i dati relativi alla richiesta, mentre l'oggetto Session ci mette a disposizione i dati della sessione.
    Nella tua realtà memorizzi delle informazioni in sessione, per cui è giusto usare l'oggetto Session.
    Nel mio codice di esempio, invece, anzichè dover gestire due metodi (il primo per impostare la variabile, poi il Factory per leggerla), ho saltato il giro prendendo i dati dalla Request, nel caso specifico la QueryString (parametri passati nella URL della richiesta).

    Se guardi nei miei esempi, infatti, il valore della stringa da utilizzare erano specificati nella parte finale delle URLs


    Quanto al tuo codice di esempio, non vedo particolari errori.
    Se il problema è come referenziare il DbContext generico per reperire la stringa di connessione, allora ti basta usare il service provider: ServiceProvider.GetService<DatabaseGenerico>()


    Se invece il tuo problema è un altro, prova a spiegare meglio quale sia, perchè non l'ho capito
  • Re: Asp.net core Connection string dinamica

    Buongiorno Pigi,
    non sò come ringraziarti anche solo per la pazienza che hai con me.

    Allora Vediamo di ricapitolare il tutto provando a darti un idea chiara di quello che sto provando a fare:

    la Prima view della mia app è la selezione del cliente ed il controller che ho fatto è questo:
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Http;
    
    namespace paghe.Controllers
    {
        public class PagheDacesController : Controller
        {
            public PagheDacesController(IHttpContextAccessor httpContextAccessor = null)
            {
                HttpContextAccessor = httpContextAccessor;
            }
            public IHttpContextAccessor HttpContextAccessor { get; private set; }
    
            //View Elenco Clienti   
            public ActionResult ElencoClientiPaghe()
            {
                return View();
            }
    
            //Seleziono Cliente
            public ActionResult Clienti(string SelCliente)
            {
                if (SelCliente == "51")
                {
                    HttpContextAccessor.HttpContext.Session.SetString("ConCliente", "51");
                    HttpContext.Session.SetString("NomeCliente", "Nome Cliente 51");
                    ViewData["NomeCliente"] = "Nome Cliente 51";
                }
                if (SelCliente == "56")
                {
                    HttpContextAccessor.HttpContext.Session.SetString("ConCliente", "56");
                    HttpContext.Session.SetString("NomeCliente", "Nome Cliente 56");
                    ViewData["NomeCliente"] = "Nome Cliente 56";
                }
                return RedirectToAction("Login", "LoginUser");
            }
    
    ti ho messo solo 2 cliente per Brevità.

    La mia idea è seleziono dalla View il Cliente e mi salvo le sue informazioni. ConCliente e Nome Cliente
    Dopo aver Selezionato il Cliente vado alla View del Login
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using paghe.ViewModels;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Configuration;
    using Microsoft.EntityFrameworkCore;
    using System.Data.SqlClient;
    using Microsoft.Extensions.Options;
    using Microsoft.AspNetCore.Authorization;
    using System.Security.Claims;
    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.Extensions.DependencyInjection;
    
    namespace paghe.Controllers
    {
        public class LoginUserController : Controller
        {
    
        private readonly PagheContext context;
        public LoginUserController(PagheContext context)
        {
          this.context = context;
        }
    
            [HttpGet]
            public ActionResult Login()
            {
                ViewData["NomeCliente"] = HttpContext.Session.GetString("NomeCliente");
                return View();
            }
    
            [HttpPost]
            public ActionResult Login(UtenteLoginModel Utente, string returnUrl)
            {
                if (ModelState.IsValid)
                {
                    string NomeAccesso = IsValid(Utente.NomeUtente, Utente.Password);
                    string Ruolo = HttpContext.Session.GetString("Ruolo");
                    if (NomeAccesso != String.Empty)
                    {
    
                       var claims = new[] { new Claim("NameUser", NomeAccesso), new Claim(ClaimTypes.Role, Ruolo) };
                       var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
                       return RedirectToLocal(returnUrl);
                    }
                    else
                    {
                        ModelState.AddModelError("", "Dati non corretti.");
                    }
                }
                return View(Utente);
            }
    
            private ActionResult RedirectToLocal(string returnUrl)
            {
                if (Url.IsLocalUrl(returnUrl))
                    return Redirect(returnUrl);
                else
                    return RedirectToAction("MenuPaghe", "PagheDaces");
    
            }
            public ActionResult Logout()
            {
                return RedirectToAction("Index", "Home");
            }
    
            private string IsValid(string NomeUtente, string password)
            {
                string NomeAccesso = String.Empty;
    
                using (var context = new PagheContext())
                {
                    var User = context.Users.FromSqlRaw("SELECT Password, Utenti.Id, NomeUtente, Ruoli.NomeRuolo FROM Utenti INNER JOIN UtentiInRuoli ON Utenti.ID = UtentiInRuoli.IDUtente " +
                                                            "INNER JOIN Ruoli ON UtentiInRuoli.IDRuolo = Ruoli.ID WHERE(Utenti.NomeUtente = '" + NomeUtente + "')").Single();
    
                    if (User != null)
                    {
                        if (User.Password == (password))
                        {
                            NomeAccesso = User.NomeUtente;
                            HttpContext.Session.SetString("Ruolo", User.NomeRuolo);
                        }
                    }
                    return NomeAccesso;
                }
            }
       }
    }
    

    Quindi la logica sarebbe:
    Io Seleziono il Cliente, aggancio il DataBase di riferimento vado sulla View Login se l'utente è corretto vado al Menu del Cliente.


    il DatabaseFactory che mi hai aiuto a scrivere dovrebbe servire ad indentificare il database (se non ho capito male), in questo caso tramite un semplice query ma sarebbe più comodo tramite un altro DB, ed è questo:
    sing System;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Primitives;
    
    namespace paghe
    {
        public class DatabaseFactory
        {
            public DatabaseFactory(IServiceProvider provider, IHttpContextAccessor httpContextAccessor = null)
            {
                ServiceProvider = provider;
                HttpContextAccessor = httpContextAccessor;
            }
    
            public IServiceProvider ServiceProvider { get; private set; }
            public IHttpContextAccessor HttpContextAccessor { get; private set; }
    
            public PagheContext GetDatabase()
            {
                if (HttpContextAccessor == null) return new PagheContext("Niente http context");
                //HttpContextAccessor.HttpContext.Request.Query.TryGetValue("ConCliente", out StringValues connectionId);
                string connectionId = HttpContextAccessor.HttpContext.Session.GetString("ConCliente");
    
                switch (connectionId.ToString().ToUpper())
                {
                    case "51":
                        return new PagheContext("Server= 192.168.1.103\\SQLDACES,****; Database=*************db1;User ID=***; Password=*****;");
                    case "56":
                        return new PagheContext("Server= 192.168.1.103\\SQLDACES,****; Database=*************db2;User ID=***; Password=*****;");
                    default:
                        return new PagheContext("Server= 192.168.1.103\\SQLDACES,****; Database=*************db1;User ID=***; Password=*****;");
               }
            }
         }
    }
    
    come vedi ho sospeso il codice che HttpAccessor Request che hai scritto tu ed ho messo la Session perchè non capisco come popolarlo,
    (credo che dovrei metterlo nel controller del' ELenco Cliente).

    e questa è la classe del dbcontext
    
    using Microsoft.EntityFrameworkCore;
    using paghe.Models;
    using paghe.ViewModels;
    using Microsoft.Extensions.Configuration;
    
    namespace paghe
    {
        public class PagheContext : DbContext
        {
            public PagheContext(string connectionString)
            {
                ConnectionString = connectionString;
            }
            public string ConnectionString { get; private set; }
    
            public PagheContext()
            {
            }
    
            public PagheContext(DbContextOptions<PagheContext> options)
             : base(options)
            {
            }
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                if (!optionsBuilder.IsConfigured)
                {
                    optionsBuilder.UseSqlServer(ConnectionString);
                }
            }
    
            public DbSet<User> Users { get; set; }
            public DbSet<Dipendenti> Dipendenti { get; set; }
      }
    }
    


    Ora Secondo quello che pensavo di aver capito dovrebbe funzionare così:
    1. vado nell' elenco Clienti, lì selezionando il Cliente identifico il Codice Del Cliente tramite la classe PagheDacesController.
    2. il Valore passa alla Classe DatabaseFactory per indentificare tramite il ConCliente la stringa di Connessione.
    3. mi collego al DataBase desiderato tramite la Classe PagheContext.
    4. vado alla View Login e tramite il suo controller controllo che l' utente sia autorizzato ed entro nella View menu del Cliente.

    se lancio l app in locale al momento di accedere al menu tramite il Login mi dà questo errore:
    ArgumentNullException: Value cannot be null. (Parameter 'connectionString')
    Microsoft.EntityFrameworkCore.Utilities.Check.NotEmpty(string value, string parameterName)
    Microsoft.EntityFrameworkCore.SqlServerDbContextOptionsExtensions.UseSqlServer(DbContextOptionsBuilder optionsBuilder, string connectionString, Action<SqlServerDbContextOptionsBuilder> sqlServerOptionsAction)
    paghe.PagheContext.OnConfiguring(DbContextOptionsBuilder optionsBuilder) in PagheContext.cs
    + optionsBuilder.UseSqlServer(ConnectionString);
    Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
    Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
    Microsoft.EntityFrameworkCore.DbContext.get_Model()
    Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.get_EntityType()
    Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.CheckState()
    Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.get_EntityQueryable()
    Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.System.Linq.IQueryable.get_Provider()
    Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.FromSqlRaw<TEntity>(DbSet<TEntity> source, string sql, object[] parameters)
    paghe.Controllers.LoginUserController.IsValid(string NomeUtente, string password) in LoginUserController.cs
    + var User = context.Users.FromSqlRaw("SELECT Password, Utenti.Id, NomeUtente, Ruoli.NomeRuolo FROM Utenti INNER JOIN UtentiInRuoli ON Utenti.ID = UtentiInRuoli.IDUtente " +
    paghe.Controllers.LoginUserController.Login(UtenteLoginModel Utente, string returnUrl) in LoginUserController.cs
    + string NomeAccesso = IsValid(Utente.NomeUtente, Utente.Password);
    lambda_method(Closure , object , object[] )
    ovviamente se valorizzo la ConnectionString così:
    ConnectionString= "Server= 192.168.1.103\\SQLDACES,****; Database=*************db2;User ID=***; Password=*****;"
    funziona collegandosi al solo Db del Cliente.

    Per Logica penso che i problemi siano:
    nel popolare la ConnectionId perchè non la sto popolando dall' URLs ma dalla Session
    e forse nel costruttore che sto usando per accedere al Db dal Login User cioè
    
    private readonly PagheContext context;
        public LoginUserController(PagheContext context)
        {
          this.context = context;
        }
    
    Non ti ho messo le View perchè credo non ti servano per capire dove sono gli errori
    Spero di essere stato chiaro
    Grazie a presto
  • Re: Asp.net core Connection string dinamica

    Ci sono un paio di cose che non mi tornano.

    L'eccezione sollevata è di tipo ArgumentNullException che di fatto non dovrebbe capitare nel tuo contesto, poichè istanzi il DbContext passando la connection string.

    Non capisco però una cosa: perchè nel tuo PagheContext ha due costruttori? Visto che passi dalla Factory:
    - Ti basta solo il costruttore della Factory
    - Nella registrazione dei servizi non hai più bisogno di mettere "UseSqlServer" perchè di fatto il DbContext lo istanzi tu nella Factory

    Può essere che il motore di DI vada in confusione per via di queste configurazioni e quindi chiami il secondo costruttore (quello con le options) passandogli di fatto "null"?
  • Re: Asp.net core Connection string dinamica

    Vediamo di capire:
    il secondo costruttore me lo chiede:
     using (var context = new PagheContext())
                {
                    var User = context.Users.FromSqlRaw("SELECT Password, Utenti.Id, NomeUtente, Ruoli.NomeRuolo FROM Utenti INNER JOIN UtentiInRuoli ON Utenti.ID = UtentiInRuoli.IDUtente " +
                                                            "INNER JOIN Ruoli ON UtentiInRuoli.IDRuolo = Ruoli.ID WHERE(Utenti.NomeUtente = '" + NomeUtente + "')").Single();
    se non metto
    
            public PagheContext()
            {
            }
    
    mi dà errore

    la seconda cosa che mi fai notare è che ci potrebbe essere un errore qui?
    
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                  
                if (!optionsBuilder.IsConfigured)
                {
                    optionsBuilder.UseSqlServer(ConnectionString);
                }
            }
    
    e quindi lo dovrei modificare?
    magari se ti mandassi il progetto lo capiresti meglio?
  • Re: Asp.net core Connection string dinamica

    Ciao

    Diciamo che entrambe le situazioni sono casistiche che non dovresti gestire: se lavori con la dependency injection non devi mai istanziare direttamente le classi. Punto!

    Cerca di riscrivere le classi nel modo giusto, così da usare correttamente il DI e basta.

    Quanto alla condivisione del codice, meglio fare un progettino con due classi di esempio e basta.
    Se ho tempo una di queste sere ci provo
  • Re: Asp.net core Connection string dinamica

    Se potresti te ne sarei grato!
    Grazie
Devi accedere o registrarti per scrivere nel forum
18 risposte