Modularità Javascript, MVC basato su server e realtà aziendale


32

Capisco che questa sia una domanda molto ampia, ma ho lavorato su vari aspetti di questo problema individualmente e sto lottando per riunire tutti i concetti e le tecnologie.

Vorrei specificare che le risposte dovrebbero includere queste tecnologie:

  • C #
  • MVC 3 con rasoio
  • Javascript con jQuery

Tutto quanto sopra e oltre quelli (come Backbone.js , Entity Framework , ecc.) Sono i benvenuti come suggerimenti se aiutano a rispondere alla domanda che è:

Utilizzando le tecnologie sopra elencate, qual è una strategia ottimale per l'organizzazione di codice e logica mantenendo la scalabilità e la possibilità di creare un'interfaccia utente ricca, veloce e pulita?

Idealmente, l'attenzione dovrebbe essere posta su una soluzione implementata in un ambiente aziendale / aziendale. In tale nota, l'elenco delle tecnologie sopra riportato non verrà modificato, quindi per favore non offrire soluzioni con "dovresti usare xxx invece di yyy che stai utilizzando ora".

sfondo

Lavoro quotidianamente con jQuery, ho adottato MVC di ASP.NET e lavoro con C # da molto tempo. In questo modo è possibile presentare soluzioni presupponendo una conoscenza da intermedia a avanzata di tali tecnologie.

Organizzerò la domanda in parti più piccole per rendere più semplice la risposta a:

1. Struttura del progetto

Dato che sto lavorando con ASP.NET MVC (in Visual Studio 2010 ), vorrei una soluzione di struttura di directory che offra una certa accettazione del layout principale di questo tipo di applicazione. Qualcosa come il Brunch , suppongo, ma con un po 'più di dettaglio su cosa contenga ogni cartella e su come funziona con altre aree dell'app.

2. Accesso ai dati

Vorrei modulare il mio accesso ai dati il ​​più possibile, con una struttura di tipo API. Si può assumere un sacco di oggetti POCO ( User, UserGroup, Customer, OrderHeader, OrderDetails, ecc), ma ci saranno anche alcuni rapporti complessi che richiedono dati SQL intensa e attenta di rendering dell'interfaccia utente. EF + LINQ sono fantastici per il primo ma non tanto per il secondo. Non riesco a trovare qualcosa che sembra adattarsi a entrambi gli scenari senza essere eccessivamente complicato o eccessivamente semplice.

3. Organizzazione del codice lato client e rendering dell'interfaccia utente

Come la maggior parte degli sviluppatori che raccolgono jQuery per la prima volta, sono caduto nella trappola di unire il codice ovunque fosse necessario, ma l'ho trovato rapidamente accumulando e diventando brutto. Anche se da allora ho fatto passi da gigante, faccio ancora fatica a modularizzare il mio codice e lavorare con varie parti dell'interfaccia utente senza ripetere il codice.

Ad esempio, un tipico pezzo di codice che potrei scrivere sarebbe simile a questo, ho commentato le cose che mi infastidiscono ( nota che da allora sono passato all'utilizzo di chiamate differite AJAX e separato le richieste di dati effettivi dalla manipolazione DOM ):

$('#doSomethingDangerous').click(function () {
    // maybe confirm something first
    if (confirm('Are you sure you want to do this?')) {   

        // show a spinner?  something global would be preferred so I don't have to repeat this on every page 
        $('#loading').show();  

        // maybe the page should notify the user of what's going on in addition to the dialog?
        $('#results').show().html('<h2>Please wait, this may take a while...</h2>');  

        $.ajax({
            url: 'blah/DoDangerousThing',
            success: function (data) {                     
                // The results will be loaded to the DOM obviously, is there a better way to pull this type of specific code out of the data access calls?
                $('#results').empty();
                $('#results').append('<b>' + data.length + '</b> users were affected by this dangerous activity');
                $('#results').append('<ul>');

                // I've recently started to use jQuery templates for this sort of logic, is that the way to go?
                $(data).each(function (i, user) {
                    $('#results').append('<li>' + user.Username + '</li>');
                });                    
                $('#results').append('</ul>');

                // Need to hide the spinner, again would prefer to have this done elsewhere
                $('#loading').hide();
            }
        });
    }
});

Domande generali

  • Client MVC vs. server MVC? Il mio progetto è già una struttura MVC sul lato server, quindi è ancora necessario un client MVC come fornisce Backbone.js?
  • I file Javascript dovrebbero essere creati per ogni oggetto (come un OrderHeader.js) e quindi minimizzati / uniti durante la compilazione? O dovrebbe essercene uno Order.jsche ha una logica per OrderHeader, OrderDetails, Reportsetc?
  • Come devono essere gestite le query complesse? In questo momento la mia teoria principale è /Reports/Orders-By-Date/o qualcosa del genere e utilizzo una query SQL personalizzata che esegue il rendering di un set di dati personalizzato (o ViewModel) nella vista Razor. Ma per quanto riguarda il paging, l'ordinamento, ecc.? È meglio fare questo lato client o server? (presuppone un set di dati più grande - query SQL da 2 a 3 secondi)
  • Ho letto il Progetto Silk di Microsoft . È un buon modo di andare? Come si confronta con Backbone.js o altri?
  • Sono molto abituato a un'architettura di livello N, questi concetti in qualche modo lo buttano fuori dalla finestra? Sembra che MVC sia come un mucchio di mini sezioni di livello N all'interno di quello che sarebbe stato il front-end o il livello superiore in passato.

Ancora una volta, più specifiche sono le tue risposte, migliore sarà. Ho letto molta documentazione ed esempi di alto livello , sto cercando di capire meglio traducendoli in esempi del mondo reale .


2
Ti sei impegnata molto in questa domanda, ma non mi sembra una domanda StackOverflow. Forse i programmatori stackexchange potrebbero adattarsi meglio.
Punta il

3
Non sono d'accordo sul fatto che si tratti di un argomento interessante, ma Stackoverflow dovrebbe riguardare questioni oggettive . Qualcosa di simile a questa domanda è fondamentalmente il bambino poster per domande che "probabilmente solleciteranno opinioni, dibattiti, discussioni, sondaggi o discussioni estese".
Punta il

8
C'è un campo di persone che pianificano la scala più grande per tutto il tempo, mentre io porto via tranquillamente i loro affari perché hanno impiegato troppo tempo a pianificare qualcosa che non è mai successo.
Jason Sebring,

1
Sono d'accordo con @Pointy che questo appartiene allo stack dei programmatori. La tua domanda è molto interessante e la seguirò perché cerco sempre consigli. Ma non è una domanda obiettiva e finirà solo per dibattiti preferenziali. Come sempre, fai ciò che funziona meglio per la tua situazione ... nessuno di noi sa nulla della struttura della tua rete, del numero di clienti o delle statistiche del traffico o del processo di costruzione ... quindi la domanda è IN MODO troppo vaga ... tutto quello che so è evitare la seta. ;)
one.beat.consumer il

1
Questa domanda si adatta alla definizione stessa di "eccessivamente ampia" e quindi "non una vera domanda". Semmai, le singole domande dovrebbero essere poste come domande individuali con un leggero background (troppo e le persone lo contrassegneranno "non una vera domanda"). Tuttavia, fai attenzione, alcune delle singole domande che stai ponendo probabilmente verrebbero contrassegnate come "non costruttive" da sole, quindi starei attento a come le fai.
casperOne

Risposte:


10

Terry, amico mio, tu ed io dovremmo bere qualcosa. Abbiamo alcuni problemi simili.

1. Struttura del progetto: concordo con Eduardo sul fatto che la struttura delle cartelle in un'app MVC lascia a desiderare. Hai le tue cartelle Controller, Modelli e Viste standard. Ma poi la cartella Views viene suddivisa in una cartella diversa per ciascun controller, oltre a una cartella condivisa. E ogni Visualizzazioni / ControllerName o Views / Shared possono essere suddivisi in EditorTemplates e DisplayTemplates. Ma ti consente di decidere come organizzare la cartella Modelli (puoi farlo con o senza sottocartelle e dichiarazioni di spazi dei nomi aggiuntive).

Dio ti proibisce di utilizzare le aree, che duplicano la struttura di cartelle Controller, Modelli e Viste per ciascuna area.

/Areas
    /Area1Name
        /Controllers
            FirstController.cs
            SecondController.cs
            ThirdController.cs
        /Models
            (can organize all in here or in separate folders / namespaces)
        /Views
            /First
                /DisplayTemplates
                    WidgetAbc.cshtml <-- to be used by views in Views/First
                /EditorTemplates
                    WidgetAbc.cshtml <-- to be used by views in Views/First
                PartialViewAbc.cshtml <-- to be used by FirstController
            /Second
                PartialViewDef.cshtml <-- to be used by SecondController
            /Third
                PartialViewMno.cshtml <-- to be used by ThirdController
            /Shared
                /DisplayTemplates
                    WidgetXyz.cshtml <-- to be used by any view in Area1
                /EditorTemplates
                    WidgetXyz.cshtml <-- to be used by any view in Area1
                PartialViewXyz.cshtml <-- to be used anywhere in Area1
            _ViewStart.cshtml <-- area needs its own _ViewStart.cshtml
            Web.config <-- put custom HTML Helper namespaces in here
        Area1NameRegistration.cs <-- define routes for area1 here
    /Area2Name
        /Controllers
        /Models
        /Views
        Area2NameRegistration.cs <-- define routes for area2 here

/Controllers
    AccountController.cs
    HomeController.cs
/Models
/Views
    /Account
        /DisplayTemplates
            WidgetGhi.cshtml <-- to be used views in Views/Account
        /EditorTemplates
            WidgetGhi.cshtml <-- to be used views in Views/Account
        PartialViewGhi.cshtml <-- to be used by AccountController
    /Home
        (same pattern as Account, views & templates are controller-specific)
    /Shared
        /DisplayTemplates 
            EmailAddress.cshtml <-- to be used by any view in any area
            Time.cshtml <-- to be used by any view in any area
            Url.cshtml <-- to be used by any view in any area
        /EditorTemplates
            EmailAddress.cshtml <-- to be used by any view in any area
            Time.cshtml <-- to be used by any view in any area
            Url.cshtml <-- to be used by any view in any area
        _Layout.cshtml <-- master layout page with sections
        Error.cshtml <-- custom page to show if unhandled exception occurs
    _ViewStart.cshtml <-- won't be used automatically in an area
    Web.config <-- put custom HTML Helper namespaces in here

Questo significa che se stai lavorando con qualcosa come un WidgetController, devi cercare in altre cartelle per trovare i relativi WidgetViewModels, WidgetViews, WidgetEditorTemplates, WidgetDisplayTemplates, ecc. Per quanto ingombranti possano essere, mi attengo ad esso e non deviare da queste convenzioni MVC. Per quanto riguarda l'inserimento di un modello, controller e vista nella stessa cartella ma con spazi dei nomi diversi, lo evito perché utilizzo ReSharper. Sottolinea sarà uno spazio dei nomi che non corrisponde alla cartella in cui si trova la classe. So che potrei disattivare questa funzione R #, ma aiuta in altre parti del progetto.

Per i file non di classe, MVC offre contenuti e script pronti all'uso. Cerchiamo di mantenere tutti i nostri file statici / non compilati in questi luoghi, di nuovo, per seguire la convenzione. Ogni volta che incorporiamo una libreria js che utilizza temi (immagini e o css), i file dei temi vanno tutti da qualche parte sotto / contenuto. Per lo script, li abbiamo semplicemente inseriti direttamente in / script. Inizialmente questo era per ottenere JS intellisense da VS, ma ora che otteniamo JS intellisense da R # indipendentemente dal posizionamento in / script, suppongo che potremmo deviare da quello e dividere gli script per cartella per organizzare meglio. Stai usando ReSharper? È oro puro IMO.

Un altro piccolo pezzo d'oro che aiuta molto con il refactoring è T4MVC. Usando questo, non abbiamo bisogno di digitare percorsi stringa per nomi di area, nomi di controller, nomi di azioni, persino file in contenuto e script. T4MVC digita fortemente tutte le corde magiche per te. Ecco un piccolo esempio di come la struttura del tuo progetto non conta tanto se stai usando T4MVC:

// no more magic strings in route definitions
context.MapRoutes(null,
    new[] { string.Empty, "features", "features/{version}" },
    new
    {
        area = MVC.PreviewArea.Name,
        controller = MVC.PreviewArea.Features.Name,
        action = MVC.PreviewArea.Features.ActionNames.ForPreview,
        version = "december-2011-preview-1",
    },
    new { httpMethod = new HttpMethodConstraint("GET") }
);

@* T4MVC renders .min.js script versions when project is targeted for release *@
<link href="@Url.Content(Links.content.Site_css)?r=201112B" rel="stylesheet" />
<script src="@Url.Content(Links.scripts.jquery_1_7_1_js)" type="text/javascript">
</script>

@* render a route URL as if you were calling an action method directly *@
<a href="@Url.Action(MVC.MyAreaName.MyControllerName.MyActionName
    (Model.SomeId))">@Html.DisplayFor(m => m.SomeText)</a>

// call action redirects as if you were executing an action method
return RedirectToAction(MVC.Area.MyController.DoSomething(obj1.Prop, null));

2. Accesso ai dati: non ho esperienza con PetaPoco, ma sono sicuro che vale la pena dare un'occhiata. Per i report complessi, hai preso in considerazione i servizi di report di SQL Server? Oppure, stai correndo su un diverso db? Mi dispiace non sono chiaro su cosa esattamente stai chiedendo. Utilizziamo EF + LINQ, ma forniamo anche alcune conoscenze su come generare report nelle classi di dominio. Pertanto, disponiamo di un repository di chiamate al servizio di dominio delle chiamate del controller anziché di un repository di chiamate del controller direttamente. Per i report ad hoc utilizziamo SQL Reporting Services, che di nuovo non è perfetto, ma ai nostri utenti piace essere in grado di trasferire facilmente i dati in Excel e SSRS ci semplifica.

3. Organizzazione del codice lato client e rendering dell'interfaccia utente: è qui che penso di poter offrire un aiuto. Prendi una pagina dal libro di convalida discreta MVC e AJAX discreto. Considera questo:

<img id="loading_spinner" src="/path/to/img" style="display:none;" />
<h2 id="loading_results" style="display:none;">
    Please wait, this may take a while...
</h2>
<div id="results">
</div>
<input id="doSomethingDangerous" class="u-std-ajax" 
    type="button" value="I'm feeling lucky" 
    data-myapp-confirm="Are you sure you want to do this?"
    data-myapp-show="loading_spinner,loading_results" 
    data-myapp-href="blah/DoDangerousThing" />

Ignora la funzione di successo ajax per ora (ne parleremo più avanti). Puoi cavartela con un singolo script per alcune delle tue azioni:

$('.u-std-ajax').click(function () {
    // maybe confirm something first
    var clicked = this;
    var confirmMessage = $(clicked).data('myapp-confirm');
    if (confirmMessage && !confirm(confirmMessage )) { return; } 

    // show a spinner?  something global would be preferred so 
    // I dont have to repeat this on every page 
    // maybe the page should notify the user of what's going on 
    // in addition to the dialog?
    var show = $(clicked).data('myapp-show');
    if (show) {
        var i, showIds = show.split(',');
        for (i = 0; i < showIds.length; i++) {
            $('#' + showIds[i]).show();
        }
    }

    var url = $(clicked).data('myapp-href');
    if (url) {
        $.ajax({
            url: url,
            complete: function () {                     
                // Need to hide the spinner, again would prefer to 
                // have this done elsewhere
                if (show) {
                    for (i = 0; i < showIds.length; i++) {
                        $('#' + showIds[i]).hide();
                    }
                }
            }
        });
    }
});

Il codice sopra si occuperà della conferma, mostrando lo spinner, mostrando il messaggio di attesa e nascondendo il messaggio spinner / wait dopo che la chiamata ajax è stata completata. Configurare i comportamenti utilizzando gli attributi data- *, come le librerie discrete.

Domande generali

- Client MVC vs. server MVC? Non ho provato a chiarire le azioni intraprese nella funzione di successo perché sembra che il controller stia restituendo JSON. Se i tuoi controller restituiscono JSON, potresti dare un'occhiata a KnockoutJS. Knockout JS versione 2.0 è stato rilasciato oggi . Può collegarsi direttamente al tuo JSON, in modo che un clic osservabile possa associare automaticamente i dati ai tuoi modelli javascript. D'altra parte se non ti dispiace che i tuoi metodi di azione ajax restituiscano HTML anziché JSON, possono restituire l'UL già costruito con i suoi figli LI e puoi aggiungerlo a un elemento usando data-myapp-response = "risultati". La tua funzione di successo dovrebbe apparire così:

success: function(html) {
    var responseId = $(clicked).data('myapp-response');
    if (responseId) {
        $('#' + responseId).empty().html(html);
    }
}

Per riassumere la mia migliore risposta per questo, se devi restituire JSON dai tuoi metodi di azione, stai saltando la Vista lato server, quindi questo non è davvero MVC server - è solo MC. Se si restituisce PartialViewResult con html alle chiamate ajax, si tratta del server MVC. Quindi, se la tua app deve restituire dati JSON per chiamate ajax, usa il client MVVM come KnockoutJS.

Ad ogni modo, non mi piace il JS che hai pubblicato perché mescola il layout (tag html) con il comportamento (caricamento dati asincrono). La scelta del server MVC con viste HTML parziali o del client MVVM con dati viewmodel JSON puri risolverà questo problema, ma la costruzione manuale di DOM / HTML in javascript viola la separazione delle preoccupazioni.

- Creazione di file Javascript Apparentemente le funzionalità di minificazione sono disponibili in .NET 4.5 . Se segui il percorso discreto, non dovrebbe esserci nulla che ti impedisca di caricare tutto il tuo JS in 1 file di script. Starei attento a creare diversi file JS per ogni tipo di entità, finirai con un'esplosione di file JS. Ricorda, una volta caricato il file di script, il browser dovrebbe memorizzarlo nella cache per richieste future.

- Query complesse che non considero avere funzioni come impaginazione, ordinamento, ecc. Come complesse. La mia preferenza è di gestirlo con gli URL e la logica lato server, per rendere le query db limitate se necessario. Tuttavia, siamo distribuiti in Azure, quindi l'ottimizzazione delle query è importante per noi. Ad esempio: /widgets/show-{pageSize}-per-page/page-{pageNumber}/sort-by-{sortColumn}-{sortDirection}/{keyword}. EF e LINQ to Entities possono gestire l'impaginazione e l'ordinamento con metodi come .Take (), .Skip (), .OrderBy () e .OrderByDescending (), in modo da ottenere ciò di cui hai bisogno durante il viaggio db. Non ho ancora trovato la necessità di un clientlib, quindi onestamente non ne so molto. Cerca altre risposte per ulteriori consigli al riguardo.

- Progetto seta Non ne ho mai sentito parlare, dovrò verificarlo. Sono un grande fan di Steve Sanderson, dei suoi libri, del suo BeginCollectionItem HtmlHelper e del suo blog. Detto questo, non ho alcuna esperienza con KnockoutJS in produzione . Ho controllato i suoi tutorial, ma cerco di non impegnarmi in qualcosa fino a quando non è almeno la versione 2.0. Come ho già detto, KnockoutJS 2.0 è stato appena rilasciato.

- Livello N Se per livello intendi una diversa macchina fisica, allora no, non penso che nulla vada fuori da nessuna finestra. Generalmente a 3 livelli significa che hai 3 macchine. Quindi potresti avere un client grasso come livello di presentazione, che viene eseguito sul computer di un utente. Il client fat potrebbe accedere a un livello di servizio, che viene eseguito su un server delle applicazioni e restituisce XML o altro al client fat. E il livello di servizio potrebbe ottenere i suoi dati da un server SQL su una terza macchina.

MVC è un livello, su 1 livello. I controller, i modelli e le viste fanno tutti parte del livello presentazione, che è di 1 livello nell'architettura fisica. MVC implementa il modello Model-View-Controller, che è dove potresti vedere livelli aggiuntivi. Tuttavia, cerca di non pensare a questi 3 aspetti come livelli o livelli. Prova a pensare a tutti e tre come a preoccupazioni sul livello di presentazione.

Aggiornamento dopo commento pres / bus / dati

Ok, quindi stai usando il livello e il livello in modo intercambiabile. Di solito uso il termine "livello" per le divisioni logiche / di progetto / di assieme e livello per la separazione fisica della rete. Dispiace per la confusione.

Troverai un bel po 'di persone nel campo MVC che affermano che non dovresti usare i "Modelli" in MVC per il tuo modello di dati di entità, né che dovresti usare i tuoi Controller per la logica aziendale. Idealmente, i tuoi modelli dovrebbero essere ViewModels specifici per la vista. Usando qualcosa come Automapper, prendi le tue entità dal tuo modello di dominio e le DTO in ViewModels, scolpite appositamente per l'uso dalla vista.

Qualsiasi regola aziendale dovrebbe anche far parte del tuo dominio e puoi implementarle usando i servizi di dominio / modello di fabbrica / qualunque cosa sia appropriata nel tuo livello di dominio, non nel livello di presentazione MVC. I controller dovrebbero essere stupidi, anche se non altrettanto stupidi come i modelli, e dovrebbero dare la responsabilità al dominio per tutto ciò che richiede conoscenza aziendale. I controller gestiscono il flusso di richieste e risposte HTTP, ma qualsiasi cosa con un reale valore aziendale dovrebbe essere superiore al livello di remunerazione del controller.

Quindi, puoi ancora avere un'architettura a strati, con MVC come livello di presentazione. È un client del livello applicazione, livello di servizio o livello di dominio, a seconda di come lo si progetta. Ma alla fine il tuo modello di entità dovrebbe far parte del dominio, non modelli in MVC.


Sono totalmente d'accordo con questa risposta! In particolare: • Resharper è un genio di MVC ... dal controllo degli errori alla navigazione IDE, la sua utilità mi sorprende! • L' MVC lato server è quasi sempre l'approccio migliore • L'MVC non è composto da 3 livelli separati, è un singolo livello di presentazione - non ci ho mai pensato in questo modo, ma è assolutamente corretto.
Scott Rippey,

Risposta molto bella, sicuramente quello che stavo cercando a costo della mia 300 rappresentante. Le bevande sono su di me se ti trovi nella zona di Toronto :)

tra l'altro ho sempre considerato N-tier come Pres / Bus / Data indipendentemente da dove si trovassero fisicamente. Ecco perché ho detto che MVC quasi rimuove quell'architettura perché fondamentalmente combina il 3, quello che hai detto in qualche modo è d'accordo con quello ma dà anche una prospettiva diversa su di esso.

Vorrei mettere in guardia contro l'approccio ViewModel, modello per visualizzazione. Di recente mi sono imbattuto in una situazione in cui avrei desiderato in seguito di non avere questa astrazione da DTO a ViewModel. Vedi: stackoverflow.com/q/7181980/109456

Come regola generale, non mi piace vedere jQuery e invece scrivere oggetti con interfacce che qualsiasi sviluppatore sul lato server sarebbe in grado di comprendere abbastanza rapidamente con JQ o l'API DOM che svolge l'attività all'interno. Mi piace anche molto il concetto URLConfig di Django e l'ho trovato utile per impostare oggetti da implementare su pagine. Non ho idea di cosa sia la MV? le biblioteche dovrebbero fare per me però. Non si adattano perfettamente al problema, IMO e la delegazione di eventi DOM + è tutto il modello di cui ho bisogno per gestire le pagine senza essere eccessivamente legato a una struttura specifica.
Erik Reppen,

6

Non ho intenzione di scrivere una risposta completa, ma voglio condividere alcuni suggerimenti.

I miei consigli:

1. Struttura del progetto
Ho scoperto che la struttura MVC predefinita non mi va bene. In genere lavoro nel controller, nelle viste e nel modello della stessa entità (pensa al prodotto, all'ordine, al cliente) allo stesso tempo. Quindi, mi piace avere i file nella stessa cartella, ma con spazi dei nomi diversi.

2. Dati
Se vai con Linq-to-SQL o EF te ne pentirai in seguito.
Uso PetaPoco che mi permette di eseguire il recupero e l'aggiornamento di record SQL senza il problema della mappatura, ma senza imparare un nuovo modo di fare le cose e senza gli incubi delle prestazioni.

Ho un generatore di codice per creare la classe POCO iniziale con gli attributi PetaPoco e quindi cambiare la classe quando viene aggiunto o rimosso un campo.

PetaPoco funziona con classi dinamiche e standard, quindi non hai alcun compromesso (Massive è tutto dinamico e Dapper tutte le classi standard)

Genero anche un SQL master , utilizzando SqlBuilder integrato, che contiene tutti i join standard per l'entità, ma non DOVE, quindi riutilizzo lo stesso SQL per il recupero di un'entità o di un elenco.

3. Jquery È possibile standardizzare alcune parti dell'interfaccia utente utilizzando una chiamata jQuery generale (riempimento di alcuni dati all'interno dell'elemento HTML).

Ad esempio, ho questo per l'eliminazione.

var deleteLinkObj;
// delete Link
$('.jbtn-borrar').click(function () {
    deleteLinkObj = $(this);  //for future use
    $('#delete-dialog').dialog('open');
    return false; // prevents the default behaviour
});
$('#delete-dialog').dialog({
    autoOpen: false, width: 400, resizable: false, modal: true, //Dialog options
    buttons: {
        "Borrar": function () {
            $.post(deleteLinkObj[0].href, function (data) {  //Post to action
                if (data == 'OK') {
                    deleteLinkObj.closest("tr").hide('fast'); //Hide Row
                }
                else {
                    alert(data);
                }
            });
            $(this).dialog("close");
        },
        "Cancelar": function () {
            $(this).dialog("close");
        }
    }
});

Ho solo bisogno di aggiungere la classe jbtn-borrara un collegamento ipertestuale, e mostra una finestra di dialogo, elimina il record e nasconde il filetr

Ma non pensarci troppo. L'app risplenderà con piccoli tocchi in ogni vista.

Client MVC vs. server MVC
Server MVC. Sfrutta le viste parziali che puoi utilizzare nel rendering iniziale e aggiorna alcune parti con Ajax usando la stessa vista. Vedi questo eccellente articolo

Come devono essere gestite le query complesse (chiamiamolo un rapporto)
Uso una classe che ha i parametri del rapporto come proprietà (utile per l'utilizzo dell'automazione MVC) e un Generatemetodo che esegue la query e riempie un elenco di una classe personalizzata (se si avere una classe che si adatta al ViewModel)
È possibile utilizzare questa classe come modello della vista e riempire la tabella con l'elenco generato.

Project Silk di Microsoft
Overarchitected. Corri più veloce che puoi nella direzione opposta.


Divertente, mentre leggevo il Progetto Seta, continuavo a sentire questo fastidioso sentimento e non riuscivo a posizionarlo. Overarchitected potrebbe essere stato questo ...

3

1. Struttura del progetto

Ho 2 file di progetto nella mia soluzione

1) Livello Service / Business Metto tutta la mia logica di business, il codice di accesso al DB e i POCO in questo progetto separato. Non è necessario un livello di accesso ai dati se si utilizza un ORM come ORM già astrae il livello DB.

2) Il livello dell'interfaccia utente contiene tutte le visualizzazioni, i controller, i modelli, gli script e i CSS

Cerco di fare in modo che i miei controller, viste, script e CSS utilizzino una struttura di cartelle simile. Inoltre, struttura i miei file in modo che corrispondano il più possibile al percorso dell'URL. Per evitare di dover scrivere il routing personalizzato.

Utilizzare il più possibile DisplayTemplates, EditorTemplates, viste parziali e la cartella condivisa.

Quindi strutturo tutti i miei script in modo che corrispondano alle stesse aree, controller dei miei file c # Quindi avrei un file common.js nella radice un file js per pagina e un file common.js per ogni area.

File CSS Di solito ho 2 + n (dove n è il numero di aree) Il primo file CSS è CSS solo per la pagina di destinazione solo per aiutare con un tempo di caricamento della pagina più veloce (probabilmente non così importante per l'ambiente aziendale / aziendale) Secondo file CSS è un common.css che ha tutti gli stili per tutte le altre pagine. Quindi un altro file common.css per ogni area, ad esempio un file AdminArea.css che ha CSS per ogni pagina di amministrazione.

2. Accesso ai dati

Se utilizzo Entity Framework utilizzo CodeFirst perché funziona molto bene con POCOS e non hai un modello da mantenere. nHibernate è molto più potente ma ha una curva di apprendimento più intensa. Per il paging dei risultati DB ho una riutilizzabile classe c # e una vista brevettuale che uso per tutte le mie viste.

Per query complesse e generazione di report, utilizzo le procedure memorizzate. Sono molto più facili da scrivere e mantenere e offrono più potenza al LINQ. Possono anche essere riutilizzati da altri servizi come SSRS. Uso automapper per convertire il set di dati restituito agli stessi POCO utilizzati dal framework entiry.

3. Organizzazione del codice lato client e rendering dell'interfaccia utente

La risposta di Eduardo Molteni ha un buon codice di esempio. Inoltre consiglierei sicuramente di usare knockoutjs in quanto ha sia buoni modelli che attacchi. Se usi JSON per tutte le tue chiamate AJAX che uso molto, avere la mappatura automatica dell'interfaccia utente sugli oggetti JS fa risparmiare molto tempo.

Domande generali

Le query complesse dovrebbero vivere in un proc memorizzato. (vedi commento di emeraldcode.com)

Mantieni ancora la tua architettura a livelli N usando questo MVC.


1

Sono stato recentemente spostato per credere che, se hai intenzione di utilizzare le tre tecnologie che hai elencato, dovresti prima iniziare assumendo l'adozione di Orchard CMS . Credo che sia la migliore risposta singola al tuo requisito centrale:

Qual è una strategia ottimale per l'organizzazione di codice e logica mantenendo la scalabilità e la capacità di creare un'interfaccia utente ricca, veloce e pulita?

Nello scenario di Ochard, tutto ciò che non puoi affrontare attraverso i suoi meccanismi di configurazione che gestiresti o tramite l'aggiunta di moduli online gratuiti o scrivendo il tuo modulo (che ovviamente sono C #, rasoio, eccetera). L'organizzazione del codice è un punto di forza di Orchard.

Per quanto riguarda l'accesso ai dati, ci sono abbastanza pro e contro in un ORM a tutto tondo che ho anche pensato che un micro-ORM sia la soluzione migliore. Prova Massive o Dapper . Entrambi erano presenti su Hanselminutes . Riassumo i due dicendo questo: le astrazioni da SQL si interrompono quasi invariabilmente man mano che un progetto si ingrandisce. Alla fine, la migliore soluzione per l'accesso al DB è questa astrazione chiamata SQL (bit di sarcasmo, ma vero). Lascia che il micro-ORM funzioni con questo e hai l'oro.

Metti Orchard insieme ai micro-ORM e puoi tagliare l'acciaio come il burro. Ehm, il che significa che puoi sviluppare rapidamente, ridimensionare e avere un codice che è facilmente gestibile da un team che riceve la consegna.


0

Non sono sicuro di come ho perso questa domanda, ma aggiungerò i miei due centesimi due anni dopo.

Client MVC vs. server MVC? Il mio progetto è già una struttura MVC sul lato server, quindi è ancora necessario un client MVC come fornisce Backbone.js?

MVC e MV? ancor prima che venisse spinto sul lato client, si è sostanzialmente evoluto in un termine di marketing che promette davvero solo che in qualche modo i dati saranno separati da altre cose che è in gran parte una grande idea, ma non è poi così difficile per il fai-da-te. Indipendentemente dall'approccio che stai adottando, poco prima o nel bel mezzo di apportare modifiche all'HTML che influisce sulle possibilità di presentazione o interazione è il posto più terribile in assoluto per risolvere ciò che l'azienda vuole che tu faccia con i dati.

Non c'è niente di speciale nella "visualizzazione logica". Lo stesso principio dovrebbe applicarsi a tutta la logica. E cioè, non fare nulla ora che avrebbe avuto molto più senso fare prima d'ora. Quando tutte le anatre sono in fila prima di passare alcuni dati o avviare un nuovo processo, è probabile che quella fase precedente sia molto più riutilizzabile per qualsiasi altra cosa nel sistema che fa qualcosa di simile.

I file Javascript dovrebbero essere creati per ogni oggetto (come un OrderHeader.js) e quindi minimizzati / uniti durante la compilazione? O dovrebbe esserci solo un Order.js che ha una logica per OrderHeader, OrderDetails, Reports etc?

Dipende davvero da te, ma proverei a scappare dalla cosa di un file e di una classe. Non ho mai capito perché sia ​​stato utile, ad esempio, trovare il file astratto e l'interfaccia, i file che implementano, ecc ... Classificare su preoccupazioni più ampie. ctrl + f non è così difficile da usare se va un po 'lungo.

Detto questo, non dovresti mai ricombinare JS per ridurre i file sul Web. I browser memorizzano nella cache JS, quindi stai solo forzando i ricarichi dello stesso JavaScript inserendo il vecchio JS nei nuovi file. Escludendo quantità sconcertanti di JavaScript, l'unica volta in cui non dovresti avere tutti i JS sulla pagina è quando una quantità molto grande di esso che è altamente specifica per una sezione del sito senza sovrapposizioni / aree grigie non sarà mai necessaria in un dato pagina.

E FFS non si preoccupa della gestione delle dipendenze con JavaScript sul web. Require.js su siti Web di media e bassa complessità mi fa venire voglia di club sigilli per bambini. Inserisci le tue librerie di terze parti in un blocco superiore. Le tue librerie interne al secondo blocco. E poi il tuo codice di implementazione (che non dovrebbe mai essere un decimo fintanto che il tuo codice di libreria interno - cioè molto succinto, chiaro e facile da capire) in quel terzo blocco.

Come devono essere gestite le query complesse? In questo momento la mia teoria principale è / Rapporti / Ordini per data / o qualcosa del genere e utilizzo una query SQL personalizzata che esegue il rendering di un set di dati personalizzato (o ViewModel) nella vista Razor. Ma per quanto riguarda il paging, l'ordinamento, ecc.? È meglio fare questo lato client o server? (supponiamo un set di dati più grande - query SQL da 2 a 3 secondi) Ho letto il Progetto Silk di Microsoft. È un buon modo di andare? Come si confronta con Backbone.js o altri?

Onestamente, direi tutto ciò che è più facile per te che non puzza per il cliente. Le pagine Web si caricano piuttosto velocemente sulla tecnologia moderna. Se l'implementazione in Ajax è molto dolorosa per te, non farlo. Basta andare con quello che sai meglio e poi puoi avere fantasia in seguito e vedere come ti piace per il paging. Se stai costruendo una nuova complessa app da zero, inizia con Essential e premi in ordine più tardi.

Sono molto abituato a un'architettura di livello N, questi concetti in qualche modo lo buttano fuori dalla finestra? Sembra che MVC sia come un mucchio di mini sezioni di livello N all'interno di quello che sarebbe stato il front-end o il livello superiore in passato.

Dipende davvero dall'idea di fantasia di chi è MV? è. IMO, la cosa del microcosmo tende a funzionare molto bene. Una classe di widget che separa internamente dati, comunicazioni e cose relative alla vista funziona alla grande. Sul Web lato client, la cosa fondamentale, IMO, è mantenere un equilibrio nel mantenere le preoccupazioni separate senza frammentare inutilmente in piccole piccole preoccupazioni il cui rimontaggio rende difficile comprendere, riutilizzare e modificare le cose. OOP di base "duh" funziona alla grande qui. Non vuoi processi complessi. Volete ovviamente cose nominate che possono essere spostate e che si dice loro di fare cose. Ecco alcuni suggerimenti su questo fronte:

  • BACIO che l'interfaccia (OOP) non voglio vedere DOM o jQuery o qualcos'altro che un dev sul lato server che colpisce un pizzico non potrebbe capire abbastanza rapidamente nel mio codice di implementazione. Tutto quello che quella persona dovrebbe sapere è quale classe dare uno schiaffo su un contenitore div e quale passaggio a capovolgere per rendere attivo un set di UI abbastanza generico in una data pagina. Le variazioni su un tema dovrebbero comunque essere realizzate passando in oggetti opzioni ben documentati / commentati prima che debbano iniziare a guardare document.get <nulla> o capire qualcosa al di là delle basi più semplici del CSS.

  • Okay, allora come lo fai? Bene, abbiamo già un modello. Si chiama DOM. E abbiamo una delegazione di eventi. Se non stai indiscriminatamente arrestando il gorgoglio degli eventi (non farlo - è lì perché è utile) puoi prendere ogni singolo anche dal corpo se vuoi. Quindi esamina la proprietà target dell'oggetto evento passato e determina chi è "qualunque cosa". Se stai strutturando un documento HTML in modo ragionevole, non c'è motivo di non usarlo come modello di delega. Il comportamento e la struttura del contenuto sono naturalmente collegati. Va bene per i due avere identificatori sovrapposti.

  • Non pagare per l'associazione dei dati E per "pagare" intendo ovviamente "schiaffeggiare una libreria sul tuo codebase che insiste sul fatto che fai le cose solo per tutto il tempo al fine di ottenere qualche vantaggio miracoloso che in realtà non è difficile per il fai-da-te". Il sistema di eventi di JQ lo rende piuttosto semplice.

Esempio di tempo:

function PoliticianData(){ //a constructor

    var
        that = this, //I hate 'that' but example so convention

        flavorsOfLie = {

            lies: "Oh Prism? Psh... no we're all good. There's a guy keeping an eye on that.",

            damnedLies: "50% of the people chose to not give a damn when asked whether it was better to let the terrorists win or not give a damn."

        }
    ;//end instance vars

    this.updateLies = function( lieType, newData ){
        flavorsOfLie[lieType] = newData;
        $(that).trigger({type:'update', lieType:lieType, newData: newData });
    }

    //so everytime you use the updateLies method, we can have a listener respond
    //and pass the data
}

var filthyLies = new PoliticianData();

$(filthyLies).on('update', function(e){
    stickNewDataInHTMLWithSomeFuncDefinedElsewhere(e.lieType, e.newData);
} );

filthyLies.update('damnedLies','50% of the people said they didn\'t give a damn');
//oh look, WaPo's front page just changed!
  • Non nascondere il Web La principale fonte di nutrimento in tutti i primi tentativi di rendere facile il lato client per gli sviluppatori lato server e delle app che si basavano su questo punto critico. Le richieste HTTP non sono e non sono mai state complicate. Non hanno richiesto una mostruosità di livello confuso-evento-nome-a-ogni livello 18! @ # $ Ing per renderlo più facile da capire. Allo stesso modo, c'è molto da sapere sul lato client, ma non c'è motivo di nascondersi dall'HTML e dal DOM che interagiscono con esso schiaffeggiandoci sopra un grande modello gigante. È già un grande modello gigante e funziona molto bene. Tutto ciò di cui abbiamo bisogno per renderlo un po 'più gestibile sono alcune pratiche OOP sensate e alcune conoscenze JS e DOM.

  • Favorire la flessibilità

EXTjs <==== flessibilità scala ====> jQuery (non necessariamente nessuno dei suoi plug-in)

IMO, gli strumenti che ti consentono di fare rapidamente fai-da-te sono sempre la scelta migliore. Gli strumenti che hanno fatto tutto per te sono la scelta giusta solo quando nessuno è particolarmente esigente in merito ai dettagli e non ti dispiace cedere il controllo alla cosa che dovrebbe aiutarti. In realtà ho visto plug-in che convalidano l'HTML per assicurarmi di non intrufolare un diverso tipo di elemento con tutti gli stessi tratti di visualizzazione esatti. Perché? Ho solo teorie. Penso che si riduca ai completisti che odiano davvero l'idea che qualcuno usi le loro cose in un modo che non era previsto e che è sempre inevitabilmente ciò che qualcuno vuole che tu faccia nell'interfaccia utente.

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.