Architettura / stratificazione del progetto .NET MVC

9

Quando si pianifica l'architettura per un'applicazione web MVC su scala medio-larga, come si implementano gli strati per essere il più possibile disaccoppiati e facili da testare? (in pratica segui le best practice) Supponiamo che sto utilizzando il codice come accesso ai miei dati.

Faccio fatica a definire cosa sia la "logica aziendale" e come si intende interagire con il livello dati. Prendendo ad esempio una domanda di vendita di veicoli, le logiche di business sarebbero classi che eseguivano compiti come il calcolo della banda fiscale per determinati veicoli, confrontando statistiche di miglia per gallone, ecc.? Per quanto riguarda le entità aziendali (ad esempio Cars, Vans, Motorcycles), inserirò queste informazioni nel livello dati insieme alla mia classe datacontext.

Inoltre, ciò che costituirebbe una logica applicativa piuttosto che business - indovinerò cose come le convalide di sessione / input dell'utente?

Quindi, ad esempio, un controller per auto potrebbe restituire un risultato azione / vista che elenca le prime dieci vetture filtrate per tipo e miglior mpg. Quindi diciamo che ho un 'carRepo' di ICarRepository iniettato nel mio controller (usando il pattern di repository / DI), filtro le mie auto da un parametro del metodo action, ad es. var cars = carRepo.getCarsByType ("hatchback");

Quindi ho mantenuto la conoscenza dell'accesso ai dati dal mio controller utilizzando un repository, ora per mantenere la logica aziendale fuori dal controller usando un modello di dominio - var result = new MpgCalculator (cars); - Diciamo che ho bisogno della classe calcolatrice perché ha bisogno di eseguire una logica aggiuntiva per calcolare la migliore efficienza del carburante, più che caricare e filtrare le entità dal DB. Così ora ho un set di dati per la mia vista per eseguire il rendering che ha utilizzato un repository per recuperare dal livello di accesso ai dati e oggetto specifico del dominio per elaborare ed eseguire attività correlate all'attività su quei dati.

Sto facendo degli errori qui? abbiamo ancora bisogno di usare il modello di repository o posso semplicemente codificare un'interfaccia per disaccoppiare l'ORM e testare? Su questo argomento, dal momento che le mie classi di accesso ai dati concreti dbcontext si trovano nel livello dati, le definizioni dell'interfaccia devono essere inserite nel livello dominio / azienda, il che significa che se la tecnologia di accesso ai dati viene mai modificata, gli altri livelli non vengono modificati?

Da quanto ho studiato fino ad ora la mia struttura si presenta così:

MVC Internet Application - Il progetto Internet standard - i modelli qui sono ViewModels

Dominio / Livello aziendale - classi / modelli specifici del business che i controllori possono utilizzare per elaborare entità di dominio dal livello dati prima di passare alle viste pertinenti

L'astrazione del deposito è necessaria? - Ho sentito un sacco di discussioni su questo, soprattutto quando si utilizza un ORM

Livello dati - Classi entità (Auto, Furgone, Motocicletta), DbContext - Strato di tecnologia per l'accesso ai dati concreti

Chiedo scusa se i miei esempi non hanno senso, sto cercando di imparare i migliori schemi senza rendere le applicazioni inutilmente complicate!

    
posta Michael Harper 03.10.2013 - 22:08
fonte

2 risposte

24

Nella tua domanda ci sono molte parti in movimento che toccano molti concetti, ma ecco il mio consiglio di base quando si tratta di pensare a un'applicazione MVC su scala medio-grande:

Presentazione < --- > Business Logic < --- > Accesso ai dati

In primo luogo, è meglio non pensare all'app come a "un'applicazione MVC". È un'applicazione che utilizza il pattern MVC come componente di presentazione. Pensarci in questo modo ti aiuterà a separare le preoccupazioni relative alla logica aziendale dai tuoi problemi di presentazione . Forse è giusto che le piccole applicazioni impilino tutto fino all'accesso al database nella struttura MVC, ma diventerà rapidamente insostenibile per un'applicazione di dimensioni medio-grandi.

MVC (Presentazione)

Nella tua app, il componente MVC di ASP.NET dovrebbe occuparsi della trasformazione dei dati aziendali per scopi di visualizzazione (Modelli), visualizzazione dell'interfaccia utente (Visualizzazioni) e problemi di comunicazione come routing, autenticazione, autorizzazione, convalida delle richieste, gestione delle risposte e simili (controller). Se hai un codice che fa qualcos'altro, allora non appartiene al componente MVC .

Repository / ORM (Data Access)

Anche nella tua app, il livello di accesso ai dati dovrebbe riguardare il recupero e l'archiviazione di dati persistenti. Comunemente questo è sotto forma di un database relazionale, ma ci sono molti altri modi in cui i dati possono essere mantenuti. Se hai un codice che non sta leggendo o memorizzando dati persistenti, allora non appartiene al livello dati . Ho condiviso i miei pensieri sulla discussione ORM / Repository in precedenza su SO, ma per ricapitolare, non considero un ORM come la stessa cosa di un repository, per diversi motivi.

Business Logic

Quindi ora hai il tuo livello di presentazione (MVC) e il tuo livello dati (repository o ORM) ... Tutto il resto è il tuo livello di business logic (BLL). Dovrebbe essere presente tutto il codice che decide quali dati recuperare, eseguire calcoli complicati o prendere decisioni aziendali. Di solito organizzo la mia logica di business sotto forma di 'servizi', che il mio livello di presentazione può richiedere di fare il lavoro richiesto. Tutti i miei modelli di dominio esistono qui.

Il tuo approccio

Questo è dove il tuo approccio si rompe un po 'per me. Descrivi il tuo controller MVC come il luogo in cui avresti ottenuto i dati dal repository, e chiedi a MPGCalculator di fare un po 'di lavoro, ecc. Non avrei il controller fare nulla di tutto questo, ma invece delegherei tutto questo a un servizio nella BLL.

In altre parole, non inietterei un repository e MPGCalculator nel controller, ciò sta dando al controller troppe responsabilità (sta già gestendo tutte le risorse controller che ho menzionato sopra). Invece, vorrei che un servizio nel BLL gestisca tutto ciò e restituisca i risultati al controller. Il controller può quindi trasformare i risultati nel modello corretto e passarlo alla vista corretta. Il controller non ha alcuna logica di business e le uniche cose iniettate nel controller sarebbero i servizi BLL appropriati.

Operare in questo modo significa che la logica della tua attività (ad esempio, dato un insieme di veicoli, calcola l'MPG e seleziona il meglio nel peggiore dei casi ) è indipendente dalle preoccupazioni relative alla presentazione e alla persistenza. Solitamente si trova in una libreria che non conosce o non si preoccupa della strategia di persistenza dei dati né della strategia di presentazione.

    
risposta data 05.10.2013 - 01:47
fonte
0

Sembra che tutto sia corretto per la tua struttura. L'unica cosa di cui non sono sicuro è che menzioni che i modelli in MVC sono "ViewModels" e che i tuoi controller parlano con il livello del dominio. Penso che questo abbia senso se il tuo pattern predefinito è di usare il controller per accedere al livello del dominio e quindi usare i tuoi "ViewModels" come più raccolte specifiche di informazioni da più entità di dominio come ha senso per quella particolare vista. Se è quello che stai facendo, allora probabilmente stai bene.

C'è una scuola di pensiero che dovresti avere un'astrazione completa del tuo livello di dominio nell'applicazione MVC se ne hai intenzione. Personalmente, il pensiero di farlo in un'applicazione aziendale mi causa forti dolori mentali.

Preferisco usare il modello di repository per gestire l'accesso al livello dati in quanto migliora testabilità e flessibilità. Le due cose che tendono a fare i cambiamenti più drastici sono l'interfaccia utente e il database. Immaginate se alcune delle informazioni che state tirando direttamente fuori dal database siano cambiate in modo che debbano essere recuperate da una chiamata di servizio piuttosto che da una chiamata di database, o alcune delle informazioni vengono spostate in un database differente che richiede un diverso .edmx file. Il pattern del repository fornisce astrazione per supportare questo.

    
risposta data 04.10.2013 - 23:41
fonte

Leggi altre domande sui tag