Connessione a database diversi in base all'URL

-1

Sto sviluppando un'applicazione SAAS in cui: Una singola applicazione Web è ospitata in IIS, che servirà a più società e ciascuna società avrà il proprio database. L'applicazione web e i database saranno in esecuzione sullo stesso server.

La mia domanda è: qual è la procedura migliore per modificare la stringa di connessione del database in base all'URL e ogni funzione nel livello di servizio deve passare il nome di dbName / company per identificare la stringa di connessione db?

Attualmente sto passando il nome db in ogni funzione nel livello dati e restituisco la stringa di connessione. La funzione quindi si connette a db e svolge l'operazione necessaria.

Ho controllato diverse query db multi-tenant online ma non ho trovato alcuna risposta relativa alla mia query. Qualsiasi esempio di implementazione sarebbe di grande aiuto.

Il modo in cui lo faccio è il seguente:

function Send()
{

    _emailService.SendEmail(emailId, dbName);
}

public class EmailService()
{

    Public SendEmail(string emailId, string dbName)
    {
         var connStr = SQLHelper.GetConnectionStr(dbName);
         ...
         ...
         ...
         connect to db to fetch email details and then send email
    }

}
    
posta user3151766 04.12.2017 - 10:33
fonte

1 risposta

0

Esecuzione di istanze separate

Sembra che tu stia gestendo istanze multiple di un servizio logicamente separate (una per azienda). Fondamentalmente, la tua domanda riguarda il modo migliore per garantire che questo isolamento venga mantenuto.

Attualmente, l'isolamento viene raggiunto all'interno dell'applicazione. Come ha sottolineato @MetaFight, questo ha il rischio che un bug nel tuo codice possa romperlo. I candidati evidenti sono cose che vengono tenute in memoria tra le richieste, ad es. dati memorizzati nella cache.

Perché diverse istanze (logiche) del tuo servizio non sembrano aver bisogno di interagire - ad esempio i dati della società A non influenzano i dati della società B - potresti prendere in considerazione la possibilità di spostare l'isolamento dalla tua applicazione e trattarla separatamente. (Di nuovo, vedi i commenti di @ MetaFight).

Ciò riduce la complessità dell'applicazione, al costo di aumentare la complessità delle distribuzioni. Lo stato può ancora essere trapelato in questo scenario, ad es. se si commette un errore di configurazione, collegare il servizio della società A al database della società B. Tuttavia, ora hai separato questo problema dalla logica della tua applicazione e puoi utilizzare tutti gli strumenti DevOps disponibili per gestire separatamente questo problema (comune).

A partire dallo stato corrente

Tuttavia, ritengo che la tua applicazione sia già implementata, quindi gli approcci di commutazione potrebbero non essere (immediatamente) un'opzione. In tal caso, almeno la logica del dominio dovrebbe ignorare il fatto che ci sono più società e non dovrebbe mantenere lo stato tra le richieste. Forse puoi modulare la tua applicazione seguendo le seguenti linee:

  • Selettore database

    Trasforma un URL in un oggetto accessor del database. Fai tutte le richieste attraverso questo oggetto. Fai lo stesso per tutto il resto che dipende dalla compagnia.

  • Funzionalità di business

    Calcola dati, invia e-mail, ecc. Utilizza un oggetto accessor del database dove necessario. Questo modulo non sa che ci sono più aziende. Meglio ancora, inserisci l'accesso DB in un livello a sé stante e fornisci solo i dati alla tua logica aziendale.

  • Gestore richieste

    Riceve i dati della richiesta, ottiene il corretto accesso al database e lo fornisce al livello aziendale.

Questa architettura può essere notevolmente migliorata, ma questo è al di fuori della portata della domanda. (Dai un'occhiata a qui , per esempio).

Una volta che l'applicazione ha questa forma, è molto più semplice andare al passo successivo: è sufficiente che il selettore del database fornisca sempre la stessa connessione al database, che può essere letta da un file di configurazione. E poi ripeti questa configurazione tutte le volte che ti servono.

Esempio di implementazione

Questo è un esempio molto semplice. Ancora, ci sono molti modi per migliorarlo, ma questo non è specificamente correlato alla domanda. Ho mantenuto il DB fuori dalla logica di business (invio di mail) qui. Se questo è un passo troppo grande all'inizio, puoi passare l'istanza IDatabase a WelcomeMailSender e poi andare da lì.

interface IDatabase
{
    MailData GetMailDataForUser(int userId);
}

interface IDatabaseSelector
{
    IDatabase GetFromUrl(Url url);
}

class SendWelcomeMailRequestHandler
{
    private readonly IDatabaseSelector dbSelector;  // inject via constructor
    private readonly WelcomeMailSender sender;      // inject via constructor

    ResponseData HandleRequest(RequestData req)
    {
        var db = dbSelector.GetFromUrl(req.RequestUrl);
        var data = db.GetMailDataForUser(req.UserId);
        var success = sender.SendWelcomeMail(data);
        return new ResponseData() { Success = success };
    }
}

class WelcomeMailSender
{
    bool SendWelcomeMail(MailData data)
    {
        // do all the mail-sending stuff
    }
}
    
risposta data 05.12.2017 - 11:07
fonte