2009-09-30 19 views
13

Stiamo costruendo circa 10 siti MVC ASP.NET che hanno un insieme comune di funzionalità (e URL, percorsi, controllori, azioni e viste corrispondenti). I siti condivideranno anche un insieme di base di oggetti di dominio (ad esempio utenti, società) e attributi di base su tali oggetti (ad esempio nome, indirizzo, ecc.)."ereditare" siti MVC ASP.NET da un'app modello comune? (multi-tenancy)

Ma ogni sito sarà anche altamente personalizzato ed esteso dalla base. Ad esempio, il nostro sito per le grandi aziende pubbliche avrà i campi "Sussidiaria" e "Stock Symbol" sull'oggetto dominio della Società, mentre il nostro sito per le startup avrà gli attributi "Venture Firm" e "Funding". Anche l'aspetto grafico varierà considerevolmente, anche se stiamo cercando di mantenere il più fedelmente possibile l'HTML (campi modulo extra modulo per attributi di oggetti dominio extra, ecc.). Esamineremo anche le immagini con parsimonia, in modo che possiamo, ad esempio, riutilizzare la stessa grafica dei pulsanti su tutti i siti.

In ogni caso, stiamo cercando di capire il modo migliore per analizzare e progettare le cose in modo da poter riutilizzare tanto codice e quanti più test possibili senza limitare la nostra libertà di aggiungere attributi per app e variare l'interfaccia utente tra le app .

Ho familiarità con come gestire la multi-tenancy con personalizzazione limitata come si trova in StackOverflow/SuperUser/ServerFault (o MSDN/TechNet), dove l'interfaccia utente è leggermente diversa e il modello di dati è più -o meno identico. Ma quando i modelli e l'interfaccia utente sono molto diversi (ma ereditati da una base comune), sono meno sicuro di come procedere.

Sono meno preoccupato per i problemi operativi, poiché probabilmente eseguiremo ciascun sito in un appdomain separato e li ospiteremo su database separati. Sono più preoccupato di ridurre i costi di manutenzione del codice a lungo termine, aumentare l'agilità (ad esempio, aggiungere nuove funzionalità alla base senza rompere le app derivate) e realizzare risparmi sui costi di sviluppo e test a breve termine mentre costruiamo il nostro secondo, 3 °, 4 °, ecc. Sito.

Sto cercando consigli e suggerimenti di alto livello, ma anche suggerimenti concreti su come rendere reale tale guida utilizzando le pratiche MVC ASP.NET moderne.

Mi rendo conto che questa è una domanda molto generica, ma per i principianti cerco sia una guida di alto livello sia consigli pratici per capire come applicare tale guida con ASP.NET MVC, incluse cose come :

  • raccomandazioni dove splittare di base/derivati ​​attraverso progetti di Visual Studio
  • punte di controllo di origine per evitare di sborsare
  • suggerimenti dello schema di database (FWIW, i nostri database sono tutti small-- sotto 10K righe per tabella, in modo costo di sviluppo/test è più di un problema di DB perf)
  • suggerimenti su come riutilizzare Controller/Viste/ecc. corrispondente agli attributi del modello "base", in particolare riutilizzando l'interfaccia utente per cose come i moduli "nuovo cliente" che avranno un mix di attributi di base e derivati.

Chiunque ha un buon consiglio su come progettare un'app multi-tenant come questa?

risposta

2

sono coinvolto in un simile tipo di "suite" di progetti attualmente che si concentra sulla permettendo ai clienti di applicare per i prodotti on-line ma hanno requisiti molto simili per le informazioni da raccogliere, in cui le uniche differenze riguardano informazioni specifiche sui prodotti o requisiti legislativi leggermente diversi.

Una cosa che abbiamo cercato di fare è creare pagine (modello, vista e combinazioni di controller) che siano riutilizzabili di per sé, quindi qualsiasi applicazione può usare la pagina per acquisire informazioni ma reindirizzare alla pagina successiva che potrebbe essere diversa a seconda su quale tipo di prodotto viene richiesto. Per ottenere questo, utilizziamo i controller di base astratti nella forma del modello di modello di modello che contiene fondamentalmente tutta la logica del controller richiesta (compresi i metodi di azione con i relativi filtri di azione applicati), ma poi utilizziamo metodi astratti per fare le cose specifiche come il reindirizzamento al pagina successiva nel processo. Ciò significa che l'implementazione concreta del controller utilizzato dai flussi della pagina dell'applicazione specifica può contenere solo un metodo che restituisce un RedirectToActionResult corrispondente alla pagina successiva nel flusso. C'è anche un bel po 'di altre cose che gestiscono il backward e quel tipo di cose di navigazione, ma con l'aiuto dei filtri azione è possibile ottenerlo che non devi preoccuparti di questo una volta che lo fai e lavoro.

Esistono anche oggetti modello di base che contengono funzionalità comuni, sia la logica di convalida che la logica di persistenza dello stato.

I dati acquisiti durante il processo di applicazione vengono mantenuti nel database come oggetti del modello serializzato xml che possono quindi essere estratti e de-serializzati una volta completata l'applicazione e sputati in qualsiasi formato a qualsiasi sistema utilizzato dallo staff di backend applicazioni di processo.

Le implicazioni di questo sono che abbiamo una struttura di progetto che consiste in una DLL di base che contiene classi astratte di livello superiore, interfacce e classi di utilità così come helper HTML, filtri di azione ecc. Quindi abbiamo progetti mvc che contengono il implementazioni concrete dei controller di base, dei modelli ecc. nonché delle viste e delle pagine master.

La cosa più difficile è condividere le visualizzazioni e non penso che abbiamo ancora risolto questo problema. Anche se con MVC 2.0 contenente Aree penso che questo diventerà un problema minore, ma non ho ancora avuto un buon risultato. (vedi il post di Scott Gu su 2.0: http://weblogs.asp.net/scottgu/archive/2009/07/31/asp-net-mvc-v2-preview-1-released.aspx) Una cosa che ho POC che sembra funzionerà è usare un progetto MVC di base per contenere viste comuni e quindi estendere il motore di visualizzazione predefinito per cercare quel progetto sul server web quando si guarda per una vista di rendering (che è abbastanza facile da fare). Le aree però sono una soluzione molto più bella.

Per quanto riguarda il controllo del codice sorgente, stiamo utilizzando svn e penso che sia ragionevole preoccuparsi dei rami. Non è qualcosa di cui abbiamo ancora avuto a che fare, ma probabilmente andremo con git perché sembra rendere molto meno doloroso il processo di ramificazione e fusione.

Non sono sicuro se questo ti aiuta molto, ma ti consiglio di tenere in considerazione controller e modelli astratti, e anche come utilizzare gli helper HTML e le viste parziali per raggruppare funzionalità simili.

+0

Grazie a Dean per la risposta completa! Scoprirò i tuoi suggerimenti e probabilmente costruirò alcuni prototipi per indagare. –

1

Un modo per fare ciò è utilizzare la ramificazione in un sistema di controllo del codice sorgente.

Il ramo principale è per la funzionalità comune.Quindi hai un ramo per la personalizzazione e puoi unire le modifiche alla personalizzazione o tornare al ramo principale.

+0

divertente, questo è come ho fatto finora (su una base prototipo) ma ho pensato inizialmente che questo approccio sarebbe hacky e fragile rispetto ai più tradizionali approcci di sviluppo del software come l'inter-mediazione. Hai implementato la personalizzazione utilizzando il controllo del codice sorgente in progetti con una complessità significativa? –

+0

Sì, so di un'azienda che fa questo. Hanno versioni di un progetto e personalizzazioni del cliente di ogni versione. Hanno anche creato un sistema per tenere traccia del sistema installato in ogni sede del cliente e degli script di aggiornamento che devono essere eseguiti tra le versioni. –

11

Ecco cosa facciamo, e funziona abbastanza bene per circa 8 siti al momento.

  • definire un progetto di base MVC per i controller, ViewModels, HttpApplication, rotte, ecc Questo compilerà in una DLL e compromettere la maggior parte del vostro sito.

  • Creare un set di base di viste predefinite, script, immagini, ecc. Per il sito. Questi server verranno impostati come predefiniti per i singoli siti.

  • Per client, creare qualsiasi controller personalizzato, route, ecc. Di cui avrete bisogno in un progetto che viene compilato su un'altra DLL.

  • Anche per client, ricreare visualizzazioni, script, immagini che si desidera utilizzare.

Per eseguire i passaggi sopra descritti è necessario scrivere un po 'di colla. Il primo pezzo di colla è un motore di visualizzazione personalizzato. Ti consigliamo di personalizzare il motore di visualizzazione standard per cercare le viste nella cartella specifica del client e quindi la cartella predefinita. Ciò consente di sovrascrivere facilmente il layout predefinito per client.

Il secondo metodo per far funzionare tutto è che l'applicazione principale carichi i percorsi, i controller e così via dall'assembly specifico del cliente. Per fare ciò, utilizzo il Managed Extensibility Framework (MEF) per esporre un singolo metodo Register. La chiamata di questo metodo sul codice dell'assembly del mio client registra i percorsi e qualsiasi altra esigenza specifica del client.

Ecco una visione generale di ciò che il mio struttura di cartelle sito si presenta come, con SiteContent da controllare per le viste prima:

- AppContent 
    - AppContent/Static 
    - AppContent/Static/Images 
    - AppContent/Static/Scripts 
    - AppContent/Static/Styles 
    - AppContent/Views 
    - AppContent/Views/Shared 

    - SiteContent 
    - SiteContent/Static 
    - SiteContent/Static/Images 
    - SiteContent/Static/Scripts 
    - SiteContent/Static/Styles 
    - SiteContent/Views 
    - SiteContent/Views/Shared 

    - web.config 
    - Global.asax 

ho aiutanti che posso usare come SiteImage e AppImage per l'uso in mio punto di vista. Inoltre, faccio in modo che ognuno dei miei siti client utilizzi determinati nomi specifici per le loro pagine master, che non definisco mai nei miei valori predefiniti di AppContent.

Mi rendo conto che questa è una panoramica approssimativa, ma al momento funziona abbastanza bene per noi.

+1

Spero che tu possa rispondere a questo. Come si fanno i percorsi? Viene visualizzato un errore in cui la route sta trovando più istanze del controller (una nel progetto AppContent e una nel progetto SiteContent). – Chris

Problemi correlati