Architettura / stratificazione del progetto .NET MVC


11

Quando si pianifica l'architettura per un'applicazione Web MVC di medie dimensioni, come si implementano i layer per essere il più possibile disaccoppiato e facile da testare? (sostanzialmente seguo le migliori pratiche) Supponiamo che io stia usando il codice prima come accesso ai miei dati.

Faccio fatica con cosa definire "business logic" e come si intende interagire con il livello dati. Prendendo ad esempio un'applicazione di vendita di veicoli, la logica di business sarebbe quella delle classi che eseguivano attività come il calcolo della fascia fiscale per determinati veicoli, il confronto delle statistiche di miglia per gallone ecc.? Per quanto riguarda le entità aziendali (ad esempio automobili, furgoni, motociclette) le inserirò nel livello dati insieme alla mia DataContextclasse.

Inoltre, cosa costituirebbe una logica applicativa in contrapposizione al business - sto indovinando cose come le convalide dell'input della sessione / utente?

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

Quindi ho tenuto la conoscenza dell'accesso ai dati fuori dal mio controller usando un repository, ora per mantenere la logica di business fuori dal controller usando un modello di dominio - var result = new MpgCalculator (auto); - Diciamo che ho bisogno della classe calcolatrice perché deve eseguire una logica aggiuntiva per calcolare la migliore efficienza del carburante, oltre a caricare / filtrare entità dal DB. Quindi ora ho un set di dati per il mio punto di vista per il rendering che utilizzava un repository per recuperare dal livello di accesso ai dati e un oggetto specifico del dominio per elaborare ed eseguire attività correlate a tali dati.

Sto commettendo errori qui? dobbiamo ancora usare il modello di repository o posso semplicemente codificare su un'interfaccia per disaccoppiare l'ORM e testare? Su questo argomento, poiché le mie classi dbcontext di accesso ai dati concreti si trovano nel livello dati, le definizioni dell'interfaccia vanno nel livello dominio / business, il che significa che se la tecnologia di accesso ai dati viene mai modificata, i miei altri livelli non vengono effettuati?

Da quello che ho studiato finora la mia struttura appare così:

Applicazione Internet MVC -> Il progetto Internet standard - i modelli qui sono ViewModels

Dominio / Livello aziendale -> classi / modelli specifici dell'azienda che i controller possono utilizzare per elaborare entità di dominio dal livello dati prima di passare alle viste pertinenti

Astrazione del repository necessaria? -> Ho sentito molti dibattiti su questo, specialmente quando si utilizza un ORM

Livello dati -> Classi di entità (Automobile, Furgone, Motociclo), DbContext - Livello tecnologico di accesso ai dati concreti

Risposte:


26

Hai molte parti in movimento nella tua domanda, toccando molti concetti, ma ecco il mio consiglio di base quando si tratta di come pensare a un'applicazione MVC di dimensioni medio-grandi:

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

Innanzitutto, è meglio non pensare all'app come "un'applicazione MVC". È un'applicazione che utilizza il modello MVC come componente di presentazione. Pensare in questo modo ti aiuterà a separare le preoccupazioni della tua logica aziendale dalle preoccupazioni della presentazione . Forse va bene per le piccole applicazioni impilare tutto fino all'accesso al database nella struttura MVC, ma diventerà rapidamente insostenibile per un'applicazione medio-grande.

MVC (Presentazione)

Nella tua app, il componente ASP.NET MVC 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 come (controller). Se si dispone di codice che fa qualcos'altro, non appartiene al componente MVC .

Repository / ORM (accesso ai dati)

Anche nella tua app, il livello di accesso ai dati dovrebbe riguardare il recupero e l'archiviazione di dati persistenti. Comunemente è sotto forma di un database relazionale, ma ci sono molti altri modi in cui i dati possono essere mantenuti. Se si dispone di codice che non sta leggendo o memorizzando dati persistenti, 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.

Logica di business

Quindi ora hai il tuo livello presentazione (MVC) e il tuo livello dati (repository o ORM) ... Tutto il resto è il tuo livello di logica aziendale (BLL). Tutto il tuo codice che decide quali dati recuperare, o esegue calcoli complicati o prende decisioni aziendali, dovrebbe essere qui. Di solito organizzo la mia logica aziendale sotto forma di "servizi", a cui il mio livello di presentazione può fare appello per svolgere il lavoro richiesto. Tutti i miei modelli di dominio esistono qui.

Il tuo approccio

È qui che il mio approccio si interrompe un po 'per me. Descrivi il tuo controller MVC come il luogo in cui ottenere i dati dal repository e inviti MPGCalculator a fare un po 'di lavoro, ecc. nel BLL.

In altre parole, non inietterei un repository e un MPGCalculator nel controller, questo sta dando troppa responsabilità al controller (sta già gestendo tutte le cose del controller che ho menzionato sopra). Invece, vorrei avere un servizio nel BLL per gestire tutto ciò e restituire i risultati al controller. Il controller può quindi trasformare i risultati nel modello corretto e passarli alla vista corretta. Il controller non ha alcuna logica aziendale e le uniche cose iniettate nel controller sarebbero i servizi BLL appropriati.

Farlo in questo modo significa che la tua logica aziendale (ad esempio, dato un insieme di veicoli, calcola l'MPG e ordina dal migliore al peggiore ) è indipendente dalle preoccupazioni di presentazione e persistenza. Di solito si troverà in una libreria che non conosce o si preoccupa della strategia di persistenza dei dati né della strategia di presentazione.


Ciao Eric, eccellente risposta - per quanto riguarda i repository, suppongo che le classi concrete vivrebbero nel livello di accesso ai dati e nel "Repository ICar" ecc. Nel livello aziendale / di servizio? Quindi potrei inserire servizi nel mio controller che può contenere 1 o più repository a seconda dei requisiti?
Michael Harper,

@MichaelHarper Sì, sembra un modo perfettamente valido per farlo.
Eric King,

1
Mentre l'autenticazione è una preoccupazione del controllore (diverse UI eseguono l'autenticazione in modo diverso) Direi che l'autorizzazione è una logica aziendale e appartiene al livello aziendale. Sei d'accordo?
Tom,

1
@tom Sì, hai un buon punto. Stavo pensando a un'autorizzazione semplice in quanto l' utente ha accesso a questo percorso , ma può esserci molto di più. La parte "molto di più" appartiene al livello aziendale.
Eric King,

1
@HunterNelson Se stai mappando in un modello di visualizzazione, la mappatura dovrebbe avvenire dove si trova la vista, nel livello di presentazione. Non avrebbe senso altrove.
Eric King,

0

Sembra che tutto sia corretto per la tua struttura. L'unica cosa di cui non sono sicuro è che dici che i modelli in MVC sono "ViewModels" e che i tuoi controller parlano al livello del dominio. Penso che questo abbia senso se il tuo modello predefinito è usare il controller per accedere al livello di dominio e quindi usare i tuoi "ViewModels" come raccolte di informazioni più specifiche della vista 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. Personalmente, il pensiero di farlo in un'applicazione enterprise mi provoca gravi dolori mentali.

Preferisco utilizzare il modello di repository per gestire l'accesso al livello dati in quanto migliora la testabilità e la flessibilità. Le due cose che tendono ad apportare le modifiche più drastiche sono l'interfaccia utente e il database. Immagina se alcune delle informazioni che stai estraendo direttamente dal database vengono modificate in modo che debbano essere recuperate da una chiamata di servizio piuttosto che da una chiamata di database, oppure se alcune delle informazioni vengono spostate in un database diverso che richiede un diverso .edmx file. Il modello di repository fornisce astrazione per supportare questo.


Grazie per la risposta William 😊 Considererei i miei oggetti business / la mia logica e le mie entità di dominio come "modelli" che il controller utilizza per elaborare le azioni degli utenti e i modelli di visualizzazione come modelli specifici che potrebbero contenere gruppi di modelli, ecc.
Michael Harper,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.